Added tests project.

This commit is contained in:
N. Taylor Mullen 2014-01-17 16:15:21 -08:00
parent 72e37d7ac6
commit af14969b54
354 changed files with 35115 additions and 0 deletions

View File

@ -5,6 +5,14 @@ VisualStudioVersion = 12.0.21005.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.Razor", "src\Microsoft.AspNet.Razor\Microsoft.AspNet.Razor.csproj", "{E75D8296-3BA6-4E67-AFEB-90FF77460B15}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{3C0D6505-79B3-49D0-B4C3-176F0F1836ED}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{92463391-81BE-462B-AC3C-78C6C760741F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.Razor.Test", "test\Microsoft.AspNet.Razor.Test\Microsoft.AspNet.Razor.Test.csproj", "{0BB62A1D-E6B5-49FA-9E3C-6AF679A66DFE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.TestCommon", "test\Microsoft.TestCommon\Microsoft.TestCommon.csproj", "{FCCC4CB7-BAF7-4A57-9F89-E5766FE536C0}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -15,8 +23,21 @@ Global
{E75D8296-3BA6-4E67-AFEB-90FF77460B15}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E75D8296-3BA6-4E67-AFEB-90FF77460B15}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E75D8296-3BA6-4E67-AFEB-90FF77460B15}.Release|Any CPU.Build.0 = Release|Any CPU
{0BB62A1D-E6B5-49FA-9E3C-6AF679A66DFE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0BB62A1D-E6B5-49FA-9E3C-6AF679A66DFE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0BB62A1D-E6B5-49FA-9E3C-6AF679A66DFE}.Release|Any CPU.ActiveCfg = Debug|Any CPU
{0BB62A1D-E6B5-49FA-9E3C-6AF679A66DFE}.Release|Any CPU.Build.0 = Debug|Any CPU
{FCCC4CB7-BAF7-4A57-9F89-E5766FE536C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FCCC4CB7-BAF7-4A57-9F89-E5766FE536C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FCCC4CB7-BAF7-4A57-9F89-E5766FE536C0}.Release|Any CPU.ActiveCfg = Debug|Any CPU
{FCCC4CB7-BAF7-4A57-9F89-E5766FE536C0}.Release|Any CPU.Build.0 = Debug|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{E75D8296-3BA6-4E67-AFEB-90FF77460B15} = {3C0D6505-79B3-49D0-B4C3-176F0F1836ED}
{0BB62A1D-E6B5-49FA-9E3C-6AF679A66DFE} = {92463391-81BE-462B-AC3C-78C6C760741F}
{FCCC4CB7-BAF7-4A57-9F89-E5766FE536C0} = {92463391-81BE-462B-AC3C-78C6C760741F}
EndGlobalSection
EndGlobal

View File

@ -37,3 +37,5 @@ using System.Runtime.InteropServices;
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: InternalsVisibleTo("Microsoft.AspNet.Razor.Test")]

View File

@ -0,0 +1,55 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using Microsoft.AspNet.Razor.Generator;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.CSharp;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.Razor.Test
{
public class CSharpRazorCodeLanguageTest
{
[Fact]
public void CreateCodeParserReturnsNewCSharpCodeParser()
{
// Arrange
RazorCodeLanguage service = new CSharpRazorCodeLanguage();
// Act
ParserBase parser = service.CreateCodeParser();
// Assert
Assert.NotNull(parser);
Assert.IsType<CSharpCodeParser>(parser);
}
[Fact]
public void CreateCodeGeneratorParserListenerReturnsNewCSharpCodeGeneratorParserListener()
{
// Arrange
RazorCodeLanguage service = new CSharpRazorCodeLanguage();
// Act
RazorEngineHost host = new RazorEngineHost(service);
RazorCodeGenerator generator = service.CreateCodeGenerator("Foo", "Bar", "Baz", host);
// Assert
Assert.NotNull(generator);
Assert.IsType<CSharpRazorCodeGenerator>(generator);
Assert.Equal("Foo", generator.ClassName);
Assert.Equal("Bar", generator.RootNamespaceName);
Assert.Equal("Baz", generator.SourceFileName);
Assert.Same(host, generator.Host);
}
[Fact]
public void CodeDomProviderTypeReturnsVBCodeProvider()
{
// Arrange
RazorCodeLanguage service = new CSharpRazorCodeLanguage();
// Assert
Assert.Equal(typeof(CSharpCodeProvider), service.CodeDomProviderType);
}
}
}

View File

@ -0,0 +1,24 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System.CodeDom;
using System.CodeDom.Compiler;
using System.IO;
using System.Text;
namespace Microsoft.AspNet.Razor.Test
{
internal static class CodeCompileUnitExtensions
{
public static string GenerateCode<T>(this CodeCompileUnit ccu) where T : CodeDomProvider, new()
{
StringBuilder output = new StringBuilder();
using (StringWriter writer = new StringWriter(output))
{
T provider = new T();
provider.GenerateCodeFromCompileUnit(ccu, writer, new CodeGeneratorOptions() { IndentString = " " });
}
return output.ToString();
}
}
}

View File

@ -0,0 +1,193 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System.Threading;
using Microsoft.AspNet.Razor.Editor;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Resources;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.AspNet.Razor.Test.Utils;
using Microsoft.AspNet.Razor.Text;
using System.Web.WebPages.TestUtils;
using Microsoft.CSharp;
using Microsoft.TestCommon;
using Moq;
using System;
namespace Microsoft.AspNet.Razor.Test.Editor
{
public class RazorEditorParserTest
{
private static readonly TestFile SimpleCSHTMLDocument = TestFile.Create("DesignTime.Simple.cshtml");
private static readonly TestFile SimpleCSHTMLDocumentGenerated = TestFile.Create("DesignTime.Simple.txt");
private const string TestLinePragmaFileName = "C:\\This\\Path\\Is\\Just\\For\\Line\\Pragmas.cshtml";
[Fact]
public void ConstructorRequiresNonNullHost()
{
Assert.ThrowsArgumentNull(() => new RazorEditorParser(null, TestLinePragmaFileName),
"host");
}
[Fact]
public void ConstructorRequiresNonNullPhysicalPath()
{
Assert.ThrowsArgumentNullOrEmptyString(() => new RazorEditorParser(CreateHost(), null),
"sourceFileName");
}
[Fact]
public void ConstructorRequiresNonEmptyPhysicalPath()
{
Assert.ThrowsArgumentNullOrEmptyString(() => new RazorEditorParser(CreateHost(), String.Empty),
"sourceFileName");
}
[Fact]
public void TreesAreDifferentReturnsTrueIfTreeStructureIsDifferent()
{
var factory = SpanFactory.CreateCsHtml();
Block original = new MarkupBlock(
factory.Markup("<p>"),
new ExpressionBlock(
factory.CodeTransition()),
factory.Markup("</p>"));
Block modified = new MarkupBlock(
factory.Markup("<p>"),
new ExpressionBlock(
factory.CodeTransition("@"),
factory.Code("f")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords, acceptTrailingDot: false)),
factory.Markup("</p>"));
ITextBuffer oldBuffer = new StringTextBuffer("<p>@</p>");
ITextBuffer newBuffer = new StringTextBuffer("<p>@f</p>");
Assert.True(BackgroundParser.TreesAreDifferent(
original, modified, new[] {
new TextChange(position: 4, oldLength: 0, oldBuffer: oldBuffer, newLength: 1, newBuffer: newBuffer)
}));
}
[Fact]
public void TreesAreDifferentReturnsFalseIfTreeStructureIsSame()
{
var factory = SpanFactory.CreateCsHtml();
Block original = new MarkupBlock(
factory.Markup("<p>"),
new ExpressionBlock(
factory.CodeTransition(),
factory.Code("f")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords, acceptTrailingDot: false)),
factory.Markup("</p>"));
factory.Reset();
Block modified = new MarkupBlock(
factory.Markup("<p>"),
new ExpressionBlock(
factory.CodeTransition(),
factory.Code("foo")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords, acceptTrailingDot: false)),
factory.Markup("</p>"));
original.LinkNodes();
modified.LinkNodes();
ITextBuffer oldBuffer = new StringTextBuffer("<p>@f</p>");
ITextBuffer newBuffer = new StringTextBuffer("<p>@foo</p>");
Assert.False(BackgroundParser.TreesAreDifferent(
original, modified, new[] {
new TextChange(position: 5, oldLength: 0, oldBuffer: oldBuffer, newLength: 2, newBuffer: newBuffer)
}));
}
[Fact]
public void CheckForStructureChangesRequiresNonNullBufferInChange()
{
TextChange change = new TextChange();
Assert.ThrowsArgument(
() => new RazorEditorParser(
CreateHost(),
"C:\\Foo.cshtml").CheckForStructureChanges(change),
"change",
String.Format(RazorResources.Structure_Member_CannotBeNull, "Buffer", "TextChange"));
}
private static RazorEngineHost CreateHost()
{
return new RazorEngineHost(new CSharpRazorCodeLanguage()) { DesignTimeMode = true };
}
[Fact]
[ReplaceCulture]
public void CheckForStructureChangesStartsReparseAndFiresDocumentParseCompletedEventIfNoAdditionalChangesQueued()
{
// Arrange
using (RazorEditorParser parser = CreateClientParser())
{
StringTextBuffer input = new StringTextBuffer(SimpleCSHTMLDocument.ReadAllText());
DocumentParseCompleteEventArgs capturedArgs = null;
ManualResetEventSlim parseComplete = new ManualResetEventSlim(false);
parser.DocumentParseComplete += (sender, args) =>
{
capturedArgs = args;
parseComplete.Set();
};
// Act
parser.CheckForStructureChanges(new TextChange(0, 0, new StringTextBuffer(String.Empty), input.Length, input));
// Assert
MiscUtils.DoWithTimeoutIfNotDebugging(parseComplete.Wait);
string generatedCode = capturedArgs.GeneratorResults.GeneratedCode.GenerateCode<CSharpCodeProvider>();
Assert.Equal(
SimpleCSHTMLDocumentGenerated.ReadAllText(),
MiscUtils.StripRuntimeVersion(generatedCode));
}
}
[Fact]
public void CheckForStructureChangesStartsFullReparseIfChangeOverlapsMultipleSpans()
{
// Arrange
RazorEditorParser parser = new RazorEditorParser(CreateHost(), TestLinePragmaFileName);
ITextBuffer original = new StringTextBuffer("Foo @bar Baz");
ITextBuffer changed = new StringTextBuffer("Foo @bap Daz");
TextChange change = new TextChange(7, 3, original, 3, changed);
ManualResetEventSlim parseComplete = new ManualResetEventSlim();
int parseCount = 0;
parser.DocumentParseComplete += (sender, args) =>
{
Interlocked.Increment(ref parseCount);
parseComplete.Set();
};
Assert.Equal(PartialParseResult.Rejected, parser.CheckForStructureChanges(new TextChange(0, 0, new StringTextBuffer(String.Empty), 12, original)));
MiscUtils.DoWithTimeoutIfNotDebugging(parseComplete.Wait); // Wait for the parse to finish
parseComplete.Reset();
// Act
PartialParseResult result = parser.CheckForStructureChanges(change);
// Assert
Assert.Equal(PartialParseResult.Rejected, result);
MiscUtils.DoWithTimeoutIfNotDebugging(parseComplete.Wait);
Assert.Equal(2, parseCount);
}
private TextChange CreateDummyChange()
{
return new TextChange(0, 0, new StringTextBuffer(String.Empty), 3, new StringTextBuffer("foo"));
}
private static Mock<RazorEditorParser> CreateMockParser()
{
return new Mock<RazorEditorParser>(CreateHost(), TestLinePragmaFileName) { CallBase = true };
}
private static RazorEditorParser CreateClientParser()
{
return new RazorEditorParser(CreateHost(), TestLinePragmaFileName);
}
}
}

View File

@ -0,0 +1,29 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
namespace Microsoft.AspNet.Razor.Test.Framework
{
public static class BlockExtensions
{
public static void LinkNodes(this Block self)
{
Span first = null;
Span previous = null;
foreach (Span span in self.Flatten())
{
if (first == null)
{
first = span;
}
span.Previous = previous;
if (previous != null)
{
previous.Next = span;
}
previous = span;
}
}
}
}

View File

@ -0,0 +1,235 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Generic;
using Microsoft.AspNet.Razor.Generator;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
namespace Microsoft.AspNet.Razor.Test.Framework
{
// The product code doesn't need this, but having subclasses for the block types makes tests much cleaner :)
public class StatementBlock : Block
{
private const BlockType ThisBlockType = BlockType.Statement;
public StatementBlock(IBlockCodeGenerator codeGenerator, IEnumerable<SyntaxTreeNode> children)
: base(ThisBlockType, children, codeGenerator)
{
}
public StatementBlock(IBlockCodeGenerator codeGenerator, params SyntaxTreeNode[] children)
: this(codeGenerator, (IEnumerable<SyntaxTreeNode>)children)
{
}
public StatementBlock(params SyntaxTreeNode[] children)
: this(BlockCodeGenerator.Null, children)
{
}
public StatementBlock(IEnumerable<SyntaxTreeNode> children)
: this(BlockCodeGenerator.Null, children)
{
}
}
public class DirectiveBlock : Block
{
private const BlockType ThisBlockType = BlockType.Directive;
public DirectiveBlock(IBlockCodeGenerator codeGenerator, IEnumerable<SyntaxTreeNode> children)
: base(ThisBlockType, children, codeGenerator)
{
}
public DirectiveBlock(IBlockCodeGenerator codeGenerator, params SyntaxTreeNode[] children)
: this(codeGenerator, (IEnumerable<SyntaxTreeNode>)children)
{
}
public DirectiveBlock(params SyntaxTreeNode[] children)
: this(BlockCodeGenerator.Null, children)
{
}
public DirectiveBlock(IEnumerable<SyntaxTreeNode> children)
: this(BlockCodeGenerator.Null, children)
{
}
}
public class FunctionsBlock : Block
{
private const BlockType ThisBlockType = BlockType.Functions;
public FunctionsBlock(IBlockCodeGenerator codeGenerator, IEnumerable<SyntaxTreeNode> children)
: base(ThisBlockType, children, codeGenerator)
{
}
public FunctionsBlock(IBlockCodeGenerator codeGenerator, params SyntaxTreeNode[] children)
: this(codeGenerator, (IEnumerable<SyntaxTreeNode>)children)
{
}
public FunctionsBlock(params SyntaxTreeNode[] children)
: this(BlockCodeGenerator.Null, children)
{
}
public FunctionsBlock(IEnumerable<SyntaxTreeNode> children)
: this(BlockCodeGenerator.Null, children)
{
}
}
public class ExpressionBlock : Block
{
private const BlockType ThisBlockType = BlockType.Expression;
public ExpressionBlock(IBlockCodeGenerator codeGenerator, IEnumerable<SyntaxTreeNode> children)
: base(ThisBlockType, children, codeGenerator)
{
}
public ExpressionBlock(IBlockCodeGenerator codeGenerator, params SyntaxTreeNode[] children)
: this(codeGenerator, (IEnumerable<SyntaxTreeNode>)children)
{
}
public ExpressionBlock(params SyntaxTreeNode[] children)
: this(new ExpressionCodeGenerator(), children)
{
}
public ExpressionBlock(IEnumerable<SyntaxTreeNode> children)
: this(new ExpressionCodeGenerator(), children)
{
}
}
public class HelperBlock : Block
{
private const BlockType ThisBlockType = BlockType.Helper;
public HelperBlock(IBlockCodeGenerator codeGenerator, IEnumerable<SyntaxTreeNode> children)
: base(ThisBlockType, children, codeGenerator)
{
}
public HelperBlock(IBlockCodeGenerator codeGenerator, params SyntaxTreeNode[] children)
: this(codeGenerator, (IEnumerable<SyntaxTreeNode>)children)
{
}
public HelperBlock(params SyntaxTreeNode[] children)
: this(BlockCodeGenerator.Null, children)
{
}
public HelperBlock(IEnumerable<SyntaxTreeNode> children)
: this(BlockCodeGenerator.Null, children)
{
}
}
public class MarkupBlock : Block
{
private const BlockType ThisBlockType = BlockType.Markup;
public MarkupBlock(IBlockCodeGenerator codeGenerator, IEnumerable<SyntaxTreeNode> children)
: base(ThisBlockType, children, codeGenerator)
{
}
public MarkupBlock(IBlockCodeGenerator codeGenerator, params SyntaxTreeNode[] children)
: this(codeGenerator, (IEnumerable<SyntaxTreeNode>)children)
{
}
public MarkupBlock(params SyntaxTreeNode[] children)
: this(BlockCodeGenerator.Null, children)
{
}
public MarkupBlock(IEnumerable<SyntaxTreeNode> children)
: this(BlockCodeGenerator.Null, children)
{
}
}
public class SectionBlock : Block
{
private const BlockType ThisBlockType = BlockType.Section;
public SectionBlock(IBlockCodeGenerator codeGenerator, IEnumerable<SyntaxTreeNode> children)
: base(ThisBlockType, children, codeGenerator)
{
}
public SectionBlock(IBlockCodeGenerator codeGenerator, params SyntaxTreeNode[] children)
: this(codeGenerator, (IEnumerable<SyntaxTreeNode>)children)
{
}
public SectionBlock(params SyntaxTreeNode[] children)
: this(BlockCodeGenerator.Null, children)
{
}
public SectionBlock(IEnumerable<SyntaxTreeNode> children)
: this(BlockCodeGenerator.Null, children)
{
}
}
public class TemplateBlock : Block
{
private const BlockType ThisBlockType = BlockType.Template;
public TemplateBlock(IBlockCodeGenerator codeGenerator, IEnumerable<SyntaxTreeNode> children)
: base(ThisBlockType, children, codeGenerator)
{
}
public TemplateBlock(IBlockCodeGenerator codeGenerator, params SyntaxTreeNode[] children)
: this(codeGenerator, (IEnumerable<SyntaxTreeNode>)children)
{
}
public TemplateBlock(params SyntaxTreeNode[] children)
: this(new TemplateBlockCodeGenerator(), children)
{
}
public TemplateBlock(IEnumerable<SyntaxTreeNode> children)
: this(new TemplateBlockCodeGenerator(), children)
{
}
}
public class CommentBlock : Block
{
private const BlockType ThisBlockType = BlockType.Comment;
public CommentBlock(IBlockCodeGenerator codeGenerator, IEnumerable<SyntaxTreeNode> children)
: base(ThisBlockType, children, codeGenerator)
{
}
public CommentBlock(IBlockCodeGenerator codeGenerator, params SyntaxTreeNode[] children)
: this(codeGenerator, (IEnumerable<SyntaxTreeNode>)children)
{
}
public CommentBlock(params SyntaxTreeNode[] children)
: this(new RazorCommentCodeGenerator(), children)
{
}
public CommentBlock(IEnumerable<SyntaxTreeNode> children)
: this(new RazorCommentCodeGenerator(), children)
{
}
}
}

View File

@ -0,0 +1,76 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Generic;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
namespace Microsoft.AspNet.Razor.Test.Framework
{
public abstract class CodeParserTestBase : ParserTestBase
{
protected abstract ISet<string> KeywordSet { get; }
protected override ParserBase SelectActiveParser(ParserBase codeParser, ParserBase markupParser)
{
return codeParser;
}
protected void ImplicitExpressionTest(string input, params RazorError[] errors)
{
ImplicitExpressionTest(input, AcceptedCharacters.NonWhiteSpace, errors);
}
protected void ImplicitExpressionTest(string input, AcceptedCharacters acceptedCharacters, params RazorError[] errors)
{
ImplicitExpressionTest(input, input, acceptedCharacters, errors);
}
protected void ImplicitExpressionTest(string input, string expected, params RazorError[] errors)
{
ImplicitExpressionTest(input, expected, AcceptedCharacters.NonWhiteSpace, errors);
}
protected override void SingleSpanBlockTest(string document, BlockType blockType, SpanKind spanType, AcceptedCharacters acceptedCharacters = AcceptedCharacters.Any)
{
SingleSpanBlockTest(document, blockType, spanType, acceptedCharacters, expectedError: null);
}
protected override void SingleSpanBlockTest(string document, string spanContent, BlockType blockType, SpanKind spanType, AcceptedCharacters acceptedCharacters = AcceptedCharacters.Any)
{
SingleSpanBlockTest(document, spanContent, blockType, spanType, acceptedCharacters, expectedErrors: null);
}
protected override void SingleSpanBlockTest(string document, BlockType blockType, SpanKind spanType, params RazorError[] expectedError)
{
SingleSpanBlockTest(document, document, blockType, spanType, expectedError);
}
protected override void SingleSpanBlockTest(string document, string spanContent, BlockType blockType, SpanKind spanType, params RazorError[] expectedErrors)
{
SingleSpanBlockTest(document, spanContent, blockType, spanType, AcceptedCharacters.Any, expectedErrors ?? new RazorError[0]);
}
protected override void SingleSpanBlockTest(string document, BlockType blockType, SpanKind spanType, AcceptedCharacters acceptedCharacters, params RazorError[] expectedError)
{
SingleSpanBlockTest(document, document, blockType, spanType, acceptedCharacters, expectedError);
}
protected override void SingleSpanBlockTest(string document, string spanContent, BlockType blockType, SpanKind spanType, AcceptedCharacters acceptedCharacters, params RazorError[] expectedErrors)
{
Block b = CreateSimpleBlockAndSpan(spanContent, blockType, spanType, acceptedCharacters);
ParseBlockTest(document, b, expectedErrors ?? new RazorError[0]);
}
protected void ImplicitExpressionTest(string input, string expected, AcceptedCharacters acceptedCharacters, params RazorError[] errors)
{
var factory = CreateSpanFactory();
ParseBlockTest(SyntaxConstants.TransitionString + input,
new ExpressionBlock(
factory.CodeTransition(),
factory.Code(expected)
.AsImplicitExpression(KeywordSet)
.Accepts(acceptedCharacters)),
errors);
}
}
}

View File

@ -0,0 +1,30 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Generic;
using Microsoft.AspNet.Razor.Parser;
namespace Microsoft.AspNet.Razor.Test.Framework
{
public abstract class CsHtmlCodeParserTestBase : CodeParserTestBase
{
protected override ISet<string> KeywordSet
{
get { return CSharpCodeParser.DefaultKeywords; }
}
protected override SpanFactory CreateSpanFactory()
{
return SpanFactory.CreateCsHtml();
}
public override ParserBase CreateMarkupParser()
{
return new HtmlMarkupParser();
}
public override ParserBase CreateCodeParser()
{
return new CSharpCodeParser();
}
}
}

View File

@ -0,0 +1,30 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Generic;
using Microsoft.AspNet.Razor.Parser;
namespace Microsoft.AspNet.Razor.Test.Framework
{
public abstract class CsHtmlMarkupParserTestBase : MarkupParserTestBase
{
protected override ISet<string> KeywordSet
{
get { return CSharpCodeParser.DefaultKeywords; }
}
protected override SpanFactory CreateSpanFactory()
{
return SpanFactory.CreateCsHtml();
}
public override ParserBase CreateMarkupParser()
{
return new HtmlMarkupParser();
}
public override ParserBase CreateCodeParser()
{
return new CSharpCodeParser();
}
}
}

View File

@ -0,0 +1,57 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.Text;
using Microsoft.AspNet.Razor.Utils;
namespace Microsoft.AspNet.Razor.Test.Framework
{
public class ErrorCollector
{
private StringBuilder _message = new StringBuilder();
private int _indent = 0;
public bool Success { get; private set; }
public string Message
{
get { return _message.ToString(); }
}
public ErrorCollector()
{
Success = true;
}
public void AddError(string msg, params object[] args)
{
Append("F", msg, args);
Success = false;
}
public void AddMessage(string msg, params object[] args)
{
Append("P", msg, args);
}
public IDisposable Indent()
{
_indent++;
return new DisposableAction(Unindent);
}
public void Unindent()
{
_indent--;
}
private void Append(string prefix, string msg, object[] args)
{
_message.Append(prefix);
_message.Append(":");
_message.Append(new String('\t', _indent));
_message.AppendFormat(msg, args);
_message.AppendLine();
}
}
}

View File

@ -0,0 +1,21 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
namespace Microsoft.AspNet.Razor.Test.Framework
{
public abstract class MarkupParserTestBase : CodeParserTestBase
{
protected override ParserBase SelectActiveParser(ParserBase codeParser, ParserBase markupParser)
{
return markupParser;
}
protected virtual void SingleSpanDocumentTest(string document, BlockType blockType, SpanKind spanType)
{
Block b = CreateSimpleBlockAndSpan(document, blockType, spanType);
ParseDocumentTest(document, b);
}
}
}

View File

@ -0,0 +1,426 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
//#define PARSER_TRACE
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using Microsoft.AspNet.Razor.Generator;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Text;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.Razor.Test.Framework
{
public abstract class ParserTestBase
{
protected static Block IgnoreOutput = new IgnoreOutputBlock();
public SpanFactory Factory { get; private set; }
protected ParserTestBase()
{
Factory = CreateSpanFactory();
}
public abstract ParserBase CreateMarkupParser();
public abstract ParserBase CreateCodeParser();
protected abstract ParserBase SelectActiveParser(ParserBase codeParser, ParserBase markupParser);
public virtual ParserContext CreateParserContext(ITextDocument input, ParserBase codeParser, ParserBase markupParser)
{
return new ParserContext(input, codeParser, markupParser, SelectActiveParser(codeParser, markupParser));
}
protected abstract SpanFactory CreateSpanFactory();
protected virtual void ParseBlockTest(string document)
{
ParseBlockTest(document, null, false, new RazorError[0]);
}
protected virtual void ParseBlockTest(string document, bool designTimeParser)
{
ParseBlockTest(document, null, designTimeParser, new RazorError[0]);
}
protected virtual void ParseBlockTest(string document, params RazorError[] expectedErrors)
{
ParseBlockTest(document, false, expectedErrors);
}
protected virtual void ParseBlockTest(string document, bool designTimeParser, params RazorError[] expectedErrors)
{
ParseBlockTest(document, null, designTimeParser, expectedErrors);
}
protected virtual void ParseBlockTest(string document, Block expectedRoot)
{
ParseBlockTest(document, expectedRoot, false, null);
}
protected virtual void ParseBlockTest(string document, Block expectedRoot, bool designTimeParser)
{
ParseBlockTest(document, expectedRoot, designTimeParser, null);
}
protected virtual void ParseBlockTest(string document, Block expectedRoot, params RazorError[] expectedErrors)
{
ParseBlockTest(document, expectedRoot, false, expectedErrors);
}
protected virtual void ParseBlockTest(string document, Block expectedRoot, bool designTimeParser, params RazorError[] expectedErrors)
{
RunParseTest(document, parser => parser.ParseBlock, expectedRoot, (expectedErrors ?? new RazorError[0]).ToList(), designTimeParser);
}
protected virtual void SingleSpanBlockTest(string document, BlockType blockType, SpanKind spanType, AcceptedCharacters acceptedCharacters = AcceptedCharacters.Any)
{
SingleSpanBlockTest(document, blockType, spanType, acceptedCharacters, expectedError: null);
}
protected virtual void SingleSpanBlockTest(string document, string spanContent, BlockType blockType, SpanKind spanType, AcceptedCharacters acceptedCharacters = AcceptedCharacters.Any)
{
SingleSpanBlockTest(document, spanContent, blockType, spanType, acceptedCharacters, expectedErrors: null);
}
protected virtual void SingleSpanBlockTest(string document, BlockType blockType, SpanKind spanType, params RazorError[] expectedError)
{
SingleSpanBlockTest(document, document, blockType, spanType, expectedError);
}
protected virtual void SingleSpanBlockTest(string document, string spanContent, BlockType blockType, SpanKind spanType, params RazorError[] expectedErrors)
{
SingleSpanBlockTest(document, spanContent, blockType, spanType, AcceptedCharacters.Any, expectedErrors ?? new RazorError[0]);
}
protected virtual void SingleSpanBlockTest(string document, BlockType blockType, SpanKind spanType, AcceptedCharacters acceptedCharacters, params RazorError[] expectedError)
{
SingleSpanBlockTest(document, document, blockType, spanType, acceptedCharacters, expectedError);
}
protected virtual void SingleSpanBlockTest(string document, string spanContent, BlockType blockType, SpanKind spanType, AcceptedCharacters acceptedCharacters, params RazorError[] expectedErrors)
{
BlockBuilder builder = new BlockBuilder();
builder.Type = blockType;
ParseBlockTest(
document,
ConfigureAndAddSpanToBlock(
builder,
Factory.Span(spanType, spanContent, spanType == SpanKind.Markup)
.Accepts(acceptedCharacters)),
expectedErrors ?? new RazorError[0]);
}
protected virtual void ParseDocumentTest(string document) {
ParseDocumentTest(document, null, false);
}
protected virtual void ParseDocumentTest(string document, Block expectedRoot) {
ParseDocumentTest(document, expectedRoot, false, null);
}
protected virtual void ParseDocumentTest(string document, Block expectedRoot, params RazorError[] expectedErrors) {
ParseDocumentTest(document, expectedRoot, false, expectedErrors);
}
protected virtual void ParseDocumentTest(string document, bool designTimeParser) {
ParseDocumentTest(document, null, designTimeParser);
}
protected virtual void ParseDocumentTest(string document, Block expectedRoot, bool designTimeParser) {
ParseDocumentTest(document, expectedRoot, designTimeParser, null);
}
protected virtual void ParseDocumentTest(string document, Block expectedRoot, bool designTimeParser, params RazorError[] expectedErrors) {
RunParseTest(document, parser => parser.ParseDocument, expectedRoot, expectedErrors, designTimeParser, parserSelector: c => c.MarkupParser);
}
protected virtual ParserResults ParseDocument(string document) {
return ParseDocument(document, designTimeParser: false);
}
protected virtual ParserResults ParseDocument(string document, bool designTimeParser) {
return RunParse(document, parser => parser.ParseDocument, designTimeParser, parserSelector: c => c.MarkupParser);
}
protected virtual ParserResults ParseBlock(string document) {
return ParseBlock(document, designTimeParser: false);
}
protected virtual ParserResults ParseBlock(string document, bool designTimeParser) {
return RunParse(document, parser => parser.ParseBlock, designTimeParser);
}
protected virtual ParserResults RunParse(string document, Func<ParserBase, Action> parserActionSelector, bool designTimeParser, Func<ParserContext, ParserBase> parserSelector = null)
{
parserSelector = parserSelector ?? (c => c.ActiveParser);
// Create the source
ParserResults results = null;
using (SeekableTextReader reader = new SeekableTextReader(document))
{
try
{
ParserBase codeParser = CreateCodeParser();
ParserBase markupParser = CreateMarkupParser();
ParserContext context = CreateParserContext(reader, codeParser, markupParser);
context.DesignTimeMode = designTimeParser;
codeParser.Context = context;
markupParser.Context = context;
// Run the parser
parserActionSelector(parserSelector(context))();
results = context.CompleteParse();
}
finally
{
if (results != null && results.Document != null)
{
WriteTraceLine(String.Empty);
WriteTraceLine("Actual Parse Tree:");
WriteNode(0, results.Document);
}
}
}
return results;
}
protected virtual void RunParseTest(string document, Func<ParserBase, Action> parserActionSelector, Block expectedRoot, IList<RazorError> expectedErrors, bool designTimeParser, Func<ParserContext, ParserBase> parserSelector = null)
{
// Create the source
ParserResults results = RunParse(document, parserActionSelector, designTimeParser, parserSelector);
// Evaluate the results
if (!ReferenceEquals(expectedRoot, IgnoreOutput))
{
EvaluateResults(results, expectedRoot, expectedErrors);
}
}
[Conditional("PARSER_TRACE")]
private void WriteNode(int indent, SyntaxTreeNode node)
{
string content = node.ToString().Replace("\r", "\\r")
.Replace("\n", "\\n")
.Replace("{", "{{")
.Replace("}", "}}");
if (indent > 0)
{
content = new String('.', indent * 2) + content;
}
WriteTraceLine(content);
Block block = node as Block;
if (block != null)
{
foreach (SyntaxTreeNode child in block.Children)
{
WriteNode(indent + 1, child);
}
}
}
public static void EvaluateResults(ParserResults results, Block expectedRoot)
{
EvaluateResults(results, expectedRoot, null);
}
public static void EvaluateResults(ParserResults results, Block expectedRoot, IList<RazorError> expectedErrors)
{
EvaluateParseTree(results.Document, expectedRoot);
EvaluateRazorErrors(results.ParserErrors, expectedErrors);
}
public static void EvaluateParseTree(Block actualRoot, Block expectedRoot)
{
// Evaluate the result
ErrorCollector collector = new ErrorCollector();
// Link all the nodes
expectedRoot.LinkNodes();
if (expectedRoot == null)
{
Assert.Null(actualRoot);
}
else
{
Assert.NotNull(actualRoot);
EvaluateSyntaxTreeNode(collector, actualRoot, expectedRoot);
if (collector.Success)
{
WriteTraceLine("Parse Tree Validation Succeeded:\r\n{0}", collector.Message);
}
else
{
Assert.True(false, String.Format("\r\n{0}", collector.Message));
}
}
}
private static void EvaluateSyntaxTreeNode(ErrorCollector collector, SyntaxTreeNode actual, SyntaxTreeNode expected)
{
if (actual == null)
{
AddNullActualError(collector, actual, expected);
}
if (actual.IsBlock != expected.IsBlock)
{
AddMismatchError(collector, actual, expected);
}
else
{
if (expected.IsBlock)
{
EvaluateBlock(collector, (Block)actual, (Block)expected);
}
else
{
EvaluateSpan(collector, (Span)actual, (Span)expected);
}
}
}
private static void EvaluateSpan(ErrorCollector collector, Span actual, Span expected)
{
if (!Equals(expected, actual))
{
AddMismatchError(collector, actual, expected);
}
else
{
AddPassedMessage(collector, expected);
}
}
private static void EvaluateBlock(ErrorCollector collector, Block actual, Block expected)
{
if (actual.Type != expected.Type || !expected.CodeGenerator.Equals(actual.CodeGenerator))
{
AddMismatchError(collector, actual, expected);
}
else
{
AddPassedMessage(collector, expected);
using (collector.Indent())
{
IEnumerator<SyntaxTreeNode> expectedNodes = expected.Children.GetEnumerator();
IEnumerator<SyntaxTreeNode> actualNodes = actual.Children.GetEnumerator();
while (expectedNodes.MoveNext())
{
if (!actualNodes.MoveNext())
{
collector.AddError("{0} - FAILED :: No more elements at this node", expectedNodes.Current);
}
else
{
EvaluateSyntaxTreeNode(collector, actualNodes.Current, expectedNodes.Current);
}
}
while (actualNodes.MoveNext())
{
collector.AddError("End of Node - FAILED :: Found Node: {0}", actualNodes.Current);
}
}
}
}
private static void AddPassedMessage(ErrorCollector collector, SyntaxTreeNode expected)
{
collector.AddMessage("{0} - PASSED", expected);
}
private static void AddMismatchError(ErrorCollector collector, SyntaxTreeNode actual, SyntaxTreeNode expected)
{
collector.AddError("{0} - FAILED :: Actual: {1}", expected, actual);
}
private static void AddNullActualError(ErrorCollector collector, SyntaxTreeNode actual, SyntaxTreeNode expected)
{
collector.AddError("{0} - FAILED :: Actual: << Null >>", expected);
}
public static void EvaluateRazorErrors(IList<RazorError> actualErrors, IList<RazorError> expectedErrors)
{
// Evaluate the errors
if (expectedErrors == null || expectedErrors.Count == 0)
{
Assert.True(actualErrors.Count == 0,
String.Format("Expected that no errors would be raised, but the following errors were:\r\n{0}", FormatErrors(actualErrors)));
}
else
{
Assert.True(expectedErrors.Count == actualErrors.Count,
String.Format("Expected that {0} errors would be raised, but {1} errors were.\r\nExpected Errors: \r\n{2}\r\nActual Errors: \r\n{3}",
expectedErrors.Count,
actualErrors.Count,
FormatErrors(expectedErrors),
FormatErrors(actualErrors)));
Assert.Equal(expectedErrors.ToArray(), actualErrors.ToArray());
}
WriteTraceLine("Expected Errors were raised:\r\n{0}", FormatErrors(expectedErrors));
}
public static string FormatErrors(IList<RazorError> errors)
{
if (errors == null)
{
return "\t<< No Errors >>";
}
StringBuilder builder = new StringBuilder();
foreach (RazorError err in errors)
{
builder.AppendFormat("\t{0}", err);
builder.AppendLine();
}
return builder.ToString();
}
[Conditional("PARSER_TRACE")]
private static void WriteTraceLine(string format, params object[] args)
{
Trace.WriteLine(String.Format(format, args));
}
protected virtual Block CreateSimpleBlockAndSpan(string spanContent, BlockType blockType, SpanKind spanType, AcceptedCharacters acceptedCharacters = AcceptedCharacters.Any)
{
SpanConstructor span = Factory.Span(spanType, spanContent, spanType == SpanKind.Markup).Accepts(acceptedCharacters);
BlockBuilder b = new BlockBuilder()
{
Type = blockType
};
return ConfigureAndAddSpanToBlock(b, span);
}
protected virtual Block ConfigureAndAddSpanToBlock(BlockBuilder block, SpanConstructor span)
{
switch (block.Type)
{
case BlockType.Markup:
span.With(new MarkupCodeGenerator());
break;
case BlockType.Statement:
span.With(new StatementCodeGenerator());
break;
case BlockType.Expression:
block.CodeGenerator = new ExpressionCodeGenerator();
span.With(new ExpressionCodeGenerator());
break;
}
block.Children.Add(span);
return block.Build();
}
private class IgnoreOutputBlock : Block
{
public IgnoreOutputBlock() : base(BlockType.Template, Enumerable.Empty<SyntaxTreeNode>(), null) { }
}
}
}

View File

@ -0,0 +1,74 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.Globalization;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Text;
using Microsoft.AspNet.Razor.Tokenizer.Symbols;
using Microsoft.Internal.Web.Utils;
namespace Microsoft.AspNet.Razor.Test.Framework
{
internal class RawTextSymbol : ISymbol
{
public SourceLocation Start { get; private set; }
public string Content { get; private set; }
public RawTextSymbol(SourceLocation start, string content)
{
if (content == null)
{
throw new ArgumentNullException("content");
}
Start = start;
Content = content;
}
public override bool Equals(object obj)
{
RawTextSymbol other = obj as RawTextSymbol;
return Equals(Start, other.Start) && Equals(Content, other.Content);
}
internal bool EquivalentTo(ISymbol sym)
{
return Equals(Start, sym.Start) && Equals(Content, sym.Content);
}
public override int GetHashCode()
{
return HashCodeCombiner.Start()
.Add(Start)
.Add(Content)
.CombinedHash;
}
public void OffsetStart(SourceLocation documentStart)
{
Start = documentStart + Start;
}
public void ChangeStart(SourceLocation newStart)
{
Start = newStart;
}
public override string ToString()
{
return String.Format(CultureInfo.InvariantCulture, "{0} RAW - [{1}]", Start, Content);
}
internal void CalculateStart(Span prev)
{
if (prev == null)
{
Start = SourceLocation.Zero;
}
else
{
Start = new SourceLocationTracker(prev.Start).UpdateLocation(prev.Content).CurrentLocation;
}
}
}
}

View File

@ -0,0 +1,408 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNet.Razor.Editor;
using Microsoft.AspNet.Razor.Generator;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Text;
using Microsoft.AspNet.Razor.Tokenizer;
using Microsoft.AspNet.Razor.Tokenizer.Symbols;
namespace Microsoft.AspNet.Razor.Test.Framework
{
public static class SpanFactoryExtensions
{
public static UnclassifiedCodeSpanConstructor EmptyCSharp(this SpanFactory self)
{
return new UnclassifiedCodeSpanConstructor(
self.Span(SpanKind.Code, new CSharpSymbol(self.LocationTracker.CurrentLocation, String.Empty, CSharpSymbolType.Unknown)));
}
public static UnclassifiedCodeSpanConstructor EmptyVB(this SpanFactory self)
{
return new UnclassifiedCodeSpanConstructor(
self.Span(SpanKind.Code, new VBSymbol(self.LocationTracker.CurrentLocation, String.Empty, VBSymbolType.Unknown)));
}
public static SpanConstructor EmptyHtml(this SpanFactory self)
{
return self.Span(SpanKind.Markup, new HtmlSymbol(self.LocationTracker.CurrentLocation, String.Empty, HtmlSymbolType.Unknown))
.With(new MarkupCodeGenerator());
}
public static UnclassifiedCodeSpanConstructor Code(this SpanFactory self, string content)
{
return new UnclassifiedCodeSpanConstructor(
self.Span(SpanKind.Code, content, markup: false));
}
public static SpanConstructor CodeTransition(this SpanFactory self)
{
return self.Span(SpanKind.Transition, SyntaxConstants.TransitionString, markup: false).Accepts(AcceptedCharacters.None);
}
public static SpanConstructor CodeTransition(this SpanFactory self, string content)
{
return self.Span(SpanKind.Transition, content, markup: false).Accepts(AcceptedCharacters.None);
}
public static SpanConstructor CodeTransition(this SpanFactory self, CSharpSymbolType type)
{
return self.Span(SpanKind.Transition, SyntaxConstants.TransitionString, type).Accepts(AcceptedCharacters.None);
}
public static SpanConstructor CodeTransition(this SpanFactory self, string content, CSharpSymbolType type)
{
return self.Span(SpanKind.Transition, content, type).Accepts(AcceptedCharacters.None);
}
public static SpanConstructor CodeTransition(this SpanFactory self, VBSymbolType type)
{
return self.Span(SpanKind.Transition, SyntaxConstants.TransitionString, type).Accepts(AcceptedCharacters.None);
}
public static SpanConstructor CodeTransition(this SpanFactory self, string content, VBSymbolType type)
{
return self.Span(SpanKind.Transition, content, type).Accepts(AcceptedCharacters.None);
}
public static SpanConstructor MarkupTransition(this SpanFactory self)
{
return self.Span(SpanKind.Transition, SyntaxConstants.TransitionString, markup: true).Accepts(AcceptedCharacters.None);
}
public static SpanConstructor MarkupTransition(this SpanFactory self, string content)
{
return self.Span(SpanKind.Transition, content, markup: true).Accepts(AcceptedCharacters.None);
}
public static SpanConstructor MarkupTransition(this SpanFactory self, HtmlSymbolType type)
{
return self.Span(SpanKind.Transition, SyntaxConstants.TransitionString, type).Accepts(AcceptedCharacters.None);
}
public static SpanConstructor MarkupTransition(this SpanFactory self, string content, HtmlSymbolType type)
{
return self.Span(SpanKind.Transition, content, type).Accepts(AcceptedCharacters.None);
}
public static SpanConstructor MetaCode(this SpanFactory self, string content)
{
return self.Span(SpanKind.MetaCode, content, markup: false);
}
public static SpanConstructor MetaCode(this SpanFactory self, string content, CSharpSymbolType type)
{
return self.Span(SpanKind.MetaCode, content, type);
}
public static SpanConstructor MetaCode(this SpanFactory self, string content, VBSymbolType type)
{
return self.Span(SpanKind.MetaCode, content, type);
}
public static SpanConstructor MetaMarkup(this SpanFactory self, string content)
{
return self.Span(SpanKind.MetaCode, content, markup: true);
}
public static SpanConstructor MetaMarkup(this SpanFactory self, string content, HtmlSymbolType type)
{
return self.Span(SpanKind.MetaCode, content, type);
}
public static SpanConstructor Comment(this SpanFactory self, string content, CSharpSymbolType type)
{
return self.Span(SpanKind.Comment, content, type);
}
public static SpanConstructor Comment(this SpanFactory self, string content, VBSymbolType type)
{
return self.Span(SpanKind.Comment, content, type);
}
public static SpanConstructor Comment(this SpanFactory self, string content, HtmlSymbolType type)
{
return self.Span(SpanKind.Comment, content, type);
}
public static SpanConstructor Markup(this SpanFactory self, string content)
{
return self.Span(SpanKind.Markup, content, markup: true).With(new MarkupCodeGenerator());
}
public static SpanConstructor Markup(this SpanFactory self, params string[] content)
{
return self.Span(SpanKind.Markup, content, markup: true).With(new MarkupCodeGenerator());
}
public static SourceLocation GetLocationAndAdvance(this SourceLocationTracker self, string content)
{
SourceLocation ret = self.CurrentLocation;
self.UpdateLocation(content);
return ret;
}
}
public class SpanFactory
{
public Func<ITextDocument, ITokenizer> MarkupTokenizerFactory { get; set; }
public Func<ITextDocument, ITokenizer> CodeTokenizerFactory { get; set; }
public SourceLocationTracker LocationTracker { get; private set; }
public static SpanFactory CreateCsHtml()
{
return new SpanFactory()
{
MarkupTokenizerFactory = doc => new HtmlTokenizer(doc),
CodeTokenizerFactory = doc => new CSharpTokenizer(doc)
};
}
public static SpanFactory CreateVbHtml()
{
return new SpanFactory()
{
MarkupTokenizerFactory = doc => new HtmlTokenizer(doc),
CodeTokenizerFactory = doc => new VBTokenizer(doc)
};
}
public SpanFactory()
{
LocationTracker = new SourceLocationTracker();
}
public SpanConstructor Span(SpanKind kind, string content, CSharpSymbolType type)
{
return CreateSymbolSpan(kind, content, st => new CSharpSymbol(st, content, type));
}
public SpanConstructor Span(SpanKind kind, string content, VBSymbolType type)
{
return CreateSymbolSpan(kind, content, st => new VBSymbol(st, content, type));
}
public SpanConstructor Span(SpanKind kind, string content, HtmlSymbolType type)
{
return CreateSymbolSpan(kind, content, st => new HtmlSymbol(st, content, type));
}
public SpanConstructor Span(SpanKind kind, string content, bool markup)
{
return new SpanConstructor(kind, Tokenize(new[] { content }, markup));
}
public SpanConstructor Span(SpanKind kind, string[] content, bool markup)
{
return new SpanConstructor(kind, Tokenize(content, markup));
}
public SpanConstructor Span(SpanKind kind, params ISymbol[] symbols)
{
return new SpanConstructor(kind, symbols);
}
private SpanConstructor CreateSymbolSpan(SpanKind kind, string content, Func<SourceLocation, ISymbol> ctor)
{
SourceLocation start = LocationTracker.CurrentLocation;
LocationTracker.UpdateLocation(content);
return new SpanConstructor(kind, new[] { ctor(start) });
}
public void Reset()
{
LocationTracker.CurrentLocation = SourceLocation.Zero;
}
private IEnumerable<ISymbol> Tokenize(IEnumerable<string> contentFragments, bool markup)
{
return contentFragments.SelectMany(fragment => Tokenize(fragment, markup));
}
private IEnumerable<ISymbol> Tokenize(string content, bool markup)
{
ITokenizer tok = MakeTokenizer(markup, new SeekableTextReader(content));
ISymbol sym;
ISymbol last = null;
while ((sym = tok.NextSymbol()) != null)
{
OffsetStart(sym, LocationTracker.CurrentLocation);
last = sym;
yield return sym;
}
LocationTracker.UpdateLocation(content);
}
private ITokenizer MakeTokenizer(bool markup, SeekableTextReader seekableTextReader)
{
if (markup)
{
return MarkupTokenizerFactory(seekableTextReader);
}
else
{
return CodeTokenizerFactory(seekableTextReader);
}
}
private void OffsetStart(ISymbol sym, SourceLocation sourceLocation)
{
sym.OffsetStart(sourceLocation);
}
}
public static class SpanConstructorExtensions
{
public static SpanConstructor Accepts(this SpanConstructor self, AcceptedCharacters accepted)
{
return self.With(eh => eh.AcceptedCharacters = accepted);
}
public static SpanConstructor AutoCompleteWith(this SpanConstructor self, string autoCompleteString)
{
return AutoCompleteWith(self, autoCompleteString, atEndOfSpan: false);
}
public static SpanConstructor AutoCompleteWith(this SpanConstructor self, string autoCompleteString, bool atEndOfSpan)
{
return self.With(new AutoCompleteEditHandler(SpanConstructor.TestTokenizer) { AutoCompleteString = autoCompleteString, AutoCompleteAtEndOfSpan = atEndOfSpan });
}
public static SpanConstructor WithEditorHints(this SpanConstructor self, EditorHints hints)
{
return self.With(eh => eh.EditorHints = hints);
}
}
public class UnclassifiedCodeSpanConstructor
{
SpanConstructor _self;
public UnclassifiedCodeSpanConstructor(SpanConstructor self)
{
_self = self;
}
public SpanConstructor AsMetaCode()
{
_self.Builder.Kind = SpanKind.MetaCode;
return _self;
}
public SpanConstructor AsStatement()
{
return _self.With(new StatementCodeGenerator());
}
public SpanConstructor AsExpression()
{
return _self.With(new ExpressionCodeGenerator());
}
public SpanConstructor AsImplicitExpression(ISet<string> keywords)
{
return AsImplicitExpression(keywords, acceptTrailingDot: false);
}
public SpanConstructor AsImplicitExpression(ISet<string> keywords, bool acceptTrailingDot)
{
return _self.With(new ImplicitExpressionEditHandler(SpanConstructor.TestTokenizer, keywords, acceptTrailingDot))
.With(new ExpressionCodeGenerator());
}
public SpanConstructor AsFunctionsBody()
{
return _self.With(new TypeMemberCodeGenerator());
}
public SpanConstructor AsNamespaceImport(string ns, int namespaceKeywordLength)
{
return _self.With(new AddImportCodeGenerator(ns, namespaceKeywordLength));
}
public SpanConstructor Hidden()
{
return _self.With(SpanCodeGenerator.Null);
}
public SpanConstructor AsBaseType(string baseType)
{
return _self.With(new SetBaseTypeCodeGenerator(baseType));
}
public SpanConstructor AsRazorDirectiveAttribute(string key, string value)
{
return _self.With(new RazorDirectiveAttributeCodeGenerator(key, value));
}
public SpanConstructor As(ISpanCodeGenerator codeGenerator)
{
return _self.With(codeGenerator);
}
}
public class SpanConstructor
{
public SpanBuilder Builder { get; private set; }
internal static IEnumerable<ISymbol> TestTokenizer(string str)
{
yield return new RawTextSymbol(SourceLocation.Zero, str);
}
public SpanConstructor(SpanKind kind, IEnumerable<ISymbol> symbols)
{
Builder = new SpanBuilder();
Builder.Kind = kind;
Builder.EditHandler = SpanEditHandler.CreateDefault(TestTokenizer);
foreach (ISymbol sym in symbols)
{
Builder.Accept(sym);
}
}
private Span Build()
{
return Builder.Build();
}
public SpanConstructor With(ISpanCodeGenerator generator)
{
Builder.CodeGenerator = generator;
return this;
}
public SpanConstructor With(SpanEditHandler handler)
{
Builder.EditHandler = handler;
return this;
}
public SpanConstructor With(Action<ISpanCodeGenerator> generatorConfigurer)
{
generatorConfigurer(Builder.CodeGenerator);
return this;
}
public SpanConstructor With(Action<SpanEditHandler> handlerConfigurer)
{
handlerConfigurer(Builder.EditHandler);
return this;
}
public static implicit operator Span(SpanConstructor self)
{
return self.Build();
}
public SpanConstructor Hidden()
{
Builder.CodeGenerator = SpanCodeGenerator.Null;
return this;
}
}
}

View File

@ -0,0 +1,30 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Generic;
using Microsoft.AspNet.Razor.Parser;
namespace Microsoft.AspNet.Razor.Test.Framework
{
public abstract class VBHtmlCodeParserTestBase : CodeParserTestBase
{
protected override ISet<string> KeywordSet
{
get { return VBCodeParser.DefaultKeywords; }
}
protected override SpanFactory CreateSpanFactory()
{
return SpanFactory.CreateVbHtml();
}
public override ParserBase CreateMarkupParser()
{
return new HtmlMarkupParser();
}
public override ParserBase CreateCodeParser()
{
return new VBCodeParser();
}
}
}

View File

@ -0,0 +1,30 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Generic;
using Microsoft.AspNet.Razor.Parser;
namespace Microsoft.AspNet.Razor.Test.Framework
{
public abstract class VBHtmlMarkupParserTestBase : MarkupParserTestBase
{
protected override ISet<string> KeywordSet
{
get { return VBCodeParser.DefaultKeywords; }
}
protected override SpanFactory CreateSpanFactory()
{
return SpanFactory.CreateVbHtml();
}
public override ParserBase CreateMarkupParser()
{
return new HtmlMarkupParser();
}
public override ParserBase CreateCodeParser()
{
return new VBCodeParser();
}
}
}

View File

@ -0,0 +1,417 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using Microsoft.AspNet.Razor.Generator;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.Razor.Test.Generator
{
public class CSharpRazorCodeGeneratorTest : RazorCodeGeneratorTest<CSharpRazorCodeLanguage>
{
protected override string FileExtension
{
get { return "cshtml"; }
}
protected override string LanguageName
{
get { return "CS"; }
}
protected override string BaselineExtension
{
get { return "cs"; }
}
private const string TestPhysicalPath = @"C:\Bar.cshtml";
private const string TestVirtualPath = "~/Foo/Bar.cshtml";
[Fact]
public void ConstructorRequiresNonNullClassName()
{
Assert.ThrowsArgumentNullOrEmptyString(() => new CSharpRazorCodeGenerator(null, TestRootNamespaceName, TestPhysicalPath, CreateHost()), "className");
}
[Fact]
public void ConstructorRequiresNonEmptyClassName()
{
Assert.ThrowsArgumentNullOrEmptyString(() => new CSharpRazorCodeGenerator(String.Empty, TestRootNamespaceName, TestPhysicalPath, CreateHost()), "className");
}
[Fact]
public void ConstructorRequiresNonNullRootNamespaceName()
{
Assert.ThrowsArgumentNull(() => new CSharpRazorCodeGenerator("Foo", null, TestPhysicalPath, CreateHost()), "rootNamespaceName");
}
[Fact]
public void ConstructorAllowsEmptyRootNamespaceName()
{
new CSharpRazorCodeGenerator("Foo", String.Empty, TestPhysicalPath, CreateHost());
}
[Fact]
public void ConstructorRequiresNonNullHost()
{
Assert.ThrowsArgumentNull(() => new CSharpRazorCodeGenerator("Foo", TestRootNamespaceName, TestPhysicalPath, null), "host");
}
[Theory]
[InlineData("NestedCodeBlocks")]
[InlineData("CodeBlock")]
[InlineData("ExplicitExpression")]
[InlineData("MarkupInCodeBlock")]
[InlineData("Blocks")]
[InlineData("ImplicitExpression")]
[InlineData("Imports")]
[InlineData("ExpressionsInCode")]
[InlineData("FunctionsBlock")]
[InlineData("FunctionsBlock_Tabs")]
[InlineData("Templates")]
[InlineData("Sections")]
[InlineData("RazorComments")]
[InlineData("Helpers")]
[InlineData("HelpersMissingCloseParen")]
[InlineData("HelpersMissingOpenBrace")]
[InlineData("HelpersMissingOpenParen")]
[InlineData("NestedHelpers")]
[InlineData("InlineBlocks")]
[InlineData("NestedHelpers")]
[InlineData("LayoutDirective")]
[InlineData("ConditionalAttributes")]
[InlineData("ResolveUrl")]
public void CSharpCodeGeneratorCorrectlyGeneratesRunTimeCode(string testType)
{
RunTest(testType);
}
[Fact]
public void CSharpCodeGeneratorCorrectlyGeneratesMappingsForSimpleUnspacedIf()
{
RunTest("SimpleUnspacedIf",
"SimpleUnspacedIf.DesignTime.Tabs",
designTimeMode: true,
tabTest: TabTest.Tabs,
expectedDesignTimePragmas: new List<GeneratedCodeMapping>()
{
/* 01 */ new GeneratedCodeMapping(1, 2, 1, 15),
/* 02 */ new GeneratedCodeMapping(3, 13, 7, 3),
});
}
[Fact]
public void CSharpCodeGeneratorCorrectlyGeneratesMappingsForRazorCommentsAtDesignTime()
{
RunTest("RazorComments", "RazorComments.DesignTime", designTimeMode: true, tabTest: TabTest.NoTabs, expectedDesignTimePragmas: new List<GeneratedCodeMapping>()
{
/* 01 */ new GeneratedCodeMapping(4, 3, 3, 6),
/* 02 */ new GeneratedCodeMapping(5, 40, 39, 22),
/* 03 */ new GeneratedCodeMapping(6, 50, 49, 58),
/* 04 */ new GeneratedCodeMapping(12, 3, 3, 24),
/* 05 */ new GeneratedCodeMapping(13, 46, 46, 3),
/* 06 */ new GeneratedCodeMapping(15, 3, 7, 1),
/* 07 */ new GeneratedCodeMapping(15, 8, 8, 1)
});
}
[Fact]
public void CSharpCodeGeneratorCorrectlyGenerateMappingForOpenedCurlyIf()
{
OpenedIf(withTabs: true);
}
[Fact]
public void CSharpCodeGeneratorCorrectlyGenerateMappingForOpenedCurlyIfSpaces()
{
OpenedIf(withTabs: false);
}
private void OpenedIf(bool withTabs)
{
int tabOffsetForMapping = 0;
// where the test is running with tabs, the offset into the CS buffer changes for the whitespace mapping
// with spaces we get 7xspace -> offset of 8 (column = offset+1)
// with tabs we get tab + 3 spaces -> offset of 4 chars + 1 = 5
if (withTabs)
{
tabOffsetForMapping = 3;
}
RunTest("OpenedIf",
"OpenedIf.DesignTime" + (withTabs ? ".Tabs" : ""),
designTimeMode: true,
tabTest: withTabs ? TabTest.Tabs : TabTest.NoTabs,
spans: new TestSpan[]
{
new TestSpan(SpanKind.Markup, 0, 16),
new TestSpan(SpanKind.Transition, 16, 17),
new TestSpan(SpanKind.Code, 17, 31),
new TestSpan(SpanKind.Markup, 31, 38),
new TestSpan(SpanKind.Code, 38, 40),
new TestSpan(SpanKind.Markup, 40, 47),
new TestSpan(SpanKind.Code, 47, 47),
},
expectedDesignTimePragmas: new List<GeneratedCodeMapping>()
{
/* 01 */ new GeneratedCodeMapping(3, 2, 1, 14),
/* 02 */ new GeneratedCodeMapping(4, 8, 8 - tabOffsetForMapping, 2),
/* 03 */ new GeneratedCodeMapping(5, 8, 8 - tabOffsetForMapping, 0),
});
}
[Fact]
public void CSharpCodeGeneratorCorrectlyGeneratesImportStatementsAtDesignTime()
{
RunTest("Imports", "Imports.DesignTime", designTimeMode: true, tabTest: TabTest.NoTabs, expectedDesignTimePragmas: new List<GeneratedCodeMapping>()
{
/* 01 */ new GeneratedCodeMapping(1, 2, 1, 15),
/* 02 */ new GeneratedCodeMapping(2, 2, 1, 32),
/* 03 */ new GeneratedCodeMapping(3, 2, 1, 12),
/* 04 */ new GeneratedCodeMapping(5, 30, 30, 21),
/* 05 */ new GeneratedCodeMapping(6, 36, 36, 20),
});
}
[Fact]
public void CSharpCodeGeneratorCorrectlyGeneratesFunctionsBlocksAtDesignTime()
{
RunTest("FunctionsBlock",
"FunctionsBlock.DesignTime",
designTimeMode: true,
tabTest: TabTest.NoTabs,
expectedDesignTimePragmas: new List<GeneratedCodeMapping>()
{
/* 01 */ new GeneratedCodeMapping(1, 13, 13, 4),
/* 02 */ new GeneratedCodeMapping(5, 13, 13, 104),
/* 03 */ new GeneratedCodeMapping(12, 26, 26, 11)
});
}
[Fact]
public void CSharpCodeGeneratorCorrectlyGeneratesFunctionsBlocksAtDesignTimeTabs()
{
RunTest("FunctionsBlock",
"FunctionsBlock.DesignTime" + ".Tabs",
designTimeMode: true,
tabTest: TabTest.Tabs,
expectedDesignTimePragmas: new List<GeneratedCodeMapping>()
{
/* 01 */ new GeneratedCodeMapping(1, 13, 4, 4),
/* 02 */ new GeneratedCodeMapping(5, 13, 4, 104),
/* 03 */ new GeneratedCodeMapping(12, 26, 14, 11)
});
}
[Fact]
public void CSharpCodeGeneratorCorrectlyGeneratesMinimalFunctionsBlocksAtDesignTimeTabs()
{
RunTest("FunctionsBlockMinimal",
"FunctionsBlockMinimal.DesignTime" + ".Tabs",
designTimeMode: true,
tabTest: TabTest.Tabs,
expectedDesignTimePragmas: new List<GeneratedCodeMapping>()
{
/* 01 */ new GeneratedCodeMapping(3, 13, 7, 55),
});
}
[Fact]
public void CSharpCodeGeneratorCorrectlyGeneratesHiddenSpansWithinCode()
{
RunTest("HiddenSpansInCode", designTimeMode: true, tabTest: TabTest.NoTabs, expectedDesignTimePragmas: new List<GeneratedCodeMapping>
{
/* 01 */ new GeneratedCodeMapping(1, 3, 3, 6),
/* 02 */ new GeneratedCodeMapping(2, 6, 6, 5)
});
}
[Fact]
public void CSharpCodeGeneratorGeneratesCodeWithParserErrorsInDesignTimeMode()
{
RunTest("ParserError", designTimeMode: true, expectedDesignTimePragmas: new List<GeneratedCodeMapping>()
{
/* 01 */ new GeneratedCodeMapping(1, 3, 3, 31)
});
}
[Fact]
public void CSharpCodeGeneratorCorrectlyGeneratesInheritsAtRuntime()
{
RunTest("Inherits", baselineName: "Inherits.Runtime");
}
[Fact]
public void CSharpCodeGeneratorCorrectlyGeneratesInheritsAtDesigntime()
{
RunTest("Inherits", baselineName: "Inherits.Designtime", designTimeMode: true, tabTest: TabTest.NoTabs, expectedDesignTimePragmas: new List<GeneratedCodeMapping>()
{
/* 01 */ new GeneratedCodeMapping(1, 2, 7, 5),
/* 02 */ new GeneratedCodeMapping(3, 11, 11, 25),
});
}
[Fact]
public void CSharpCodeGeneratorCorrectlyGeneratesDesignTimePragmasForUnfinishedExpressionsInCode()
{
RunTest("UnfinishedExpressionInCode", tabTest: TabTest.NoTabs, designTimeMode: true, expectedDesignTimePragmas: new List<GeneratedCodeMapping>()
{
/* 01 */ new GeneratedCodeMapping(1, 3, 3, 2),
/* 02 */ new GeneratedCodeMapping(2, 2, 7, 9),
/* 03 */ new GeneratedCodeMapping(2, 11, 11, 2)
});
}
[Fact]
public void CSharpCodeGeneratorCorrectlyGeneratesDesignTimePragmasForUnfinishedExpressionsInCodeTabs()
{
RunTest("UnfinishedExpressionInCode",
"UnfinishedExpressionInCode.Tabs",
tabTest: TabTest.Tabs,
designTimeMode: true, expectedDesignTimePragmas: new List<GeneratedCodeMapping>()
{
/* 01 */ new GeneratedCodeMapping(1, 3, 3, 2),
/* 02 */ new GeneratedCodeMapping(2, 2, 7, 9),
/* 03 */ new GeneratedCodeMapping(2, 11, 5, 2)
});
}
[Fact]
public void CSharpCodeGeneratorCorrectlyGeneratesDesignTimePragmasMarkupAndExpressions()
{
RunTest("DesignTime",
designTimeMode: true,
tabTest: TabTest.NoTabs,
expectedDesignTimePragmas: new List<GeneratedCodeMapping>()
{
/* 01 */ new GeneratedCodeMapping(2, 14, 13, 36),
/* 02 */ new GeneratedCodeMapping(3, 23, 23, 1),
/* 03 */ new GeneratedCodeMapping(3, 28, 28, 15),
/* 04 */ new GeneratedCodeMapping(8, 3, 7, 12),
/* 05 */ new GeneratedCodeMapping(9, 2, 7, 4),
/* 06 */ new GeneratedCodeMapping(9, 15, 15, 3),
/* 07 */ new GeneratedCodeMapping(9, 26, 26, 1),
/* 08 */ new GeneratedCodeMapping(14, 6, 7, 3),
/* 09 */ new GeneratedCodeMapping(17, 9, 24, 7),
/* 10 */ new GeneratedCodeMapping(17, 16, 16, 26),
/* 11 */ new GeneratedCodeMapping(19, 19, 19, 9),
/* 12 */ new GeneratedCodeMapping(21, 1, 1, 1)
});
}
[Fact]
public void CSharpCodeGeneratorCorrectlyGeneratesDesignTimePragmasForImplicitExpressionStartedAtEOF()
{
RunTest("ImplicitExpressionAtEOF", designTimeMode: true, expectedDesignTimePragmas: new List<GeneratedCodeMapping>()
{
/* 01 */ new GeneratedCodeMapping(3, 2, 7, 0)
});
}
[Fact]
public void CSharpCodeGeneratorCorrectlyGeneratesDesignTimePragmasForExplicitExpressionStartedAtEOF()
{
RunTest("ExplicitExpressionAtEOF", designTimeMode: true, expectedDesignTimePragmas: new List<GeneratedCodeMapping>()
{
/* 01 */ new GeneratedCodeMapping(3, 3, 7, 0)
});
}
[Fact]
public void CSharpCodeGeneratorCorrectlyGeneratesDesignTimePragmasForCodeBlockStartedAtEOF()
{
RunTest("CodeBlockAtEOF", designTimeMode: true, expectedDesignTimePragmas: new List<GeneratedCodeMapping>()
{
/* 01 */ new GeneratedCodeMapping(1, 3, 3, 0)
});
}
[Fact]
public void CSharpCodeGeneratorCorrectlyGeneratesDesignTimePragmasForEmptyImplicitExpression()
{
RunTest("EmptyImplicitExpression", designTimeMode: true, expectedDesignTimePragmas: new List<GeneratedCodeMapping>()
{
/* 01 */ new GeneratedCodeMapping(3, 2, 7, 0)
});
}
[Fact]
public void CSharpCodeGeneratorCorrectlyGeneratesDesignTimePragmasForEmptyImplicitExpressionInCode()
{
RunTest("EmptyImplicitExpressionInCode", tabTest: TabTest.NoTabs, designTimeMode: true, expectedDesignTimePragmas: new List<GeneratedCodeMapping>()
{
/* 01 */ new GeneratedCodeMapping(1, 3, 3, 6),
/* 02 */ new GeneratedCodeMapping(2, 6, 7, 0),
/* 03 */ new GeneratedCodeMapping(2, 6, 6, 2)
});
}
[Fact]
public void CSharpCodeGeneratorCorrectlyGeneratesDesignTimePragmasForEmptyImplicitExpressionInCodeTabs()
{
RunTest("EmptyImplicitExpressionInCode",
"EmptyImplicitExpressionInCode.Tabs",
tabTest: TabTest.Tabs,
designTimeMode: true, expectedDesignTimePragmas: new List<GeneratedCodeMapping>()
{
/* 01 */ new GeneratedCodeMapping(1, 3, 3, 6),
/* 02 */ new GeneratedCodeMapping(2, 6, 7, 0),
/* 03 */ new GeneratedCodeMapping(2, 6, 3, 2)
});
}
[Fact]
public void CSharpCodeGeneratorCorrectlyGeneratesDesignTimePragmasForEmptyExplicitExpression()
{
RunTest("EmptyExplicitExpression", designTimeMode: true, expectedDesignTimePragmas: new List<GeneratedCodeMapping>()
{
/* 01 */ new GeneratedCodeMapping(3, 3, 7, 0)
});
}
[Fact]
public void CSharpCodeGeneratorCorrectlyGeneratesDesignTimePragmasForEmptyCodeBlock()
{
RunTest("EmptyCodeBlock", designTimeMode: true, expectedDesignTimePragmas: new List<GeneratedCodeMapping>()
{
/* 01 */ new GeneratedCodeMapping(3, 3, 3, 0)
});
}
[Fact]
public void CSharpCodeGeneratorDoesNotRenderLinePragmasIfGenerateLinePragmasIsSetToFalse()
{
RunTest("NoLinePragmas", generatePragmas: false);
}
[Fact]
public void CSharpCodeGeneratorRendersHelpersBlockCorrectlyWhenInstanceHelperRequested()
{
RunTest("Helpers", baselineName: "Helpers.Instance", hostConfig: h => h.StaticHelpers = false);
}
[Fact]
public void CSharpCodeGeneratorCorrectlyInstrumentsRazorCodeWhenInstrumentationRequested()
{
RunTest("Instrumented", hostConfig: host =>
{
host.EnableInstrumentation = true;
host.InstrumentedSourceFilePath = String.Format("~/{0}.cshtml", host.DefaultClassName);
});
}
[Fact]
public void CSharpCodeGeneratorGeneratesUrlsCorrectlyWithCommentsAndQuotes()
{
RunTest("HtmlCommentWithQuote_Single",
tabTest: TabTest.NoTabs);
RunTest("HtmlCommentWithQuote_Double",
tabTest: TabTest.NoTabs);
}
}
}

View File

@ -0,0 +1,65 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using Microsoft.AspNet.Razor.Generator;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.Razor.Test.Generator
{
public class GeneratedCodeMappingTest
{
[Fact]
public void GeneratedCodeMappingsAreEqualIfDataIsEqual()
{
GeneratedCodeMapping left = new GeneratedCodeMapping(12, 34, 56, 78);
GeneratedCodeMapping right = new GeneratedCodeMapping(12, 34, 56, 78);
Assert.True(left == right);
Assert.True(left.Equals(right));
Assert.True(right.Equals(left));
Assert.True(Equals(left, right));
}
[Fact]
public void GeneratedCodeMappingsAreNotEqualIfCodeLengthIsNotEqual()
{
GeneratedCodeMapping left = new GeneratedCodeMapping(12, 34, 56, 87);
GeneratedCodeMapping right = new GeneratedCodeMapping(12, 34, 56, 78);
Assert.False(left == right);
Assert.False(left.Equals(right));
Assert.False(right.Equals(left));
Assert.False(Equals(left, right));
}
[Fact]
public void GeneratedCodeMappingsAreNotEqualIfStartGeneratedColumnIsNotEqual()
{
GeneratedCodeMapping left = new GeneratedCodeMapping(12, 34, 56, 87);
GeneratedCodeMapping right = new GeneratedCodeMapping(12, 34, 65, 87);
Assert.False(left == right);
Assert.False(left.Equals(right));
Assert.False(right.Equals(left));
Assert.False(Equals(left, right));
}
[Fact]
public void GeneratedCodeMappingsAreNotEqualIfStartColumnIsNotEqual()
{
GeneratedCodeMapping left = new GeneratedCodeMapping(12, 34, 56, 87);
GeneratedCodeMapping right = new GeneratedCodeMapping(12, 43, 56, 87);
Assert.False(left == right);
Assert.False(left.Equals(right));
Assert.False(right.Equals(left));
Assert.False(Equals(left, right));
}
[Fact]
public void GeneratedCodeMappingsAreNotEqualIfStartLineIsNotEqual()
{
GeneratedCodeMapping left = new GeneratedCodeMapping(12, 34, 56, 87);
GeneratedCodeMapping right = new GeneratedCodeMapping(21, 34, 56, 87);
Assert.False(left == right);
Assert.False(left.Equals(right));
Assert.False(right.Equals(left));
Assert.False(Equals(left, right));
}
}
}

View File

@ -0,0 +1,236 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System.IO;
using System.Linq;
using Microsoft.AspNet.Razor.Generator;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.Razor.Test.Generator
{
public class PaddingTest
{
[Fact]
public void CalculatePaddingForEmptySpanReturnsZero()
{
RazorEngineHost host = CreateHost(designTime: true);
Span span = new Span(new SpanBuilder());
int padding = CodeGeneratorPaddingHelper.CalculatePadding(host, span, 0);
Assert.Equal(0, padding);
}
[Theory]
[InlineData(true, false, 4)]
[InlineData(true, false, 2)]
[InlineData(false, true, 4)]
[InlineData(false, true, 2)]
[InlineData(false, false, 4)]
[InlineData(false, false, 2)]
[InlineData(true, true, 4)]
[InlineData(true, true, 2)]
[InlineData(true, true, 1)]
[InlineData(true, true, 0)]
public void CalculatePaddingForEmptySpanWith4Spaces(bool designTime, bool isIndentingWithTabs, int tabSize)
{
RazorEngineHost host = CreateHost(designTime: designTime, isIndentingWithTabs: isIndentingWithTabs, tabSize: tabSize);
Span span = GenerateSpan(@" @{", SpanKind.Code, 3, "");
int padding = CodeGeneratorPaddingHelper.CalculatePadding(host, span, 0);
Assert.Equal(6, padding);
}
[Theory]
[InlineData(true, false, 4)]
[InlineData(true, false, 2)]
[InlineData(false, true, 4)]
[InlineData(false, true, 2)]
[InlineData(false, false, 4)]
[InlineData(false, false, 2)]
[InlineData(true, true, 4)]
[InlineData(true, true, 2)]
[InlineData(true, true, 1)]
[InlineData(true, true, 0)]
public void CalculatePaddingForIfSpanWith4Spaces(bool designTime, bool isIndentingWithTabs, int tabSize)
{
RazorEngineHost host = CreateHost(designTime: designTime, isIndentingWithTabs: isIndentingWithTabs, tabSize: tabSize);
Span span = GenerateSpan(@" @if (true)", SpanKind.Code, 2, "if (true)");
int padding = CodeGeneratorPaddingHelper.CalculatePadding(host, span, 1);
Assert.Equal(4, padding);
}
[Theory]
[InlineData(true, false, 4, 0, 4)]
[InlineData(true, false, 2, 0, 4)]
[InlineData(true, true, 4, 1, 0)]
[InlineData(true, true, 2, 2, 0)]
[InlineData(true, true, 1, 4, 0)]
[InlineData(true, true, 0, 4, 0)]
[InlineData(true, true, 3, 1, 1)]
// in non design time mode padding falls back to spaces to keep runtime code identical to v2 code.
[InlineData(false, true, 4, 0, 5)]
[InlineData(false, true, 2, 0, 5)]
[InlineData(false, false, 4, 0, 5)]
[InlineData(false, false, 2, 0, 5)]
public void VerifyPaddingForIfSpanWith4Spaces(bool designTime, bool isIndentingWithTabs, int tabSize, int numTabs, int numSpaces)
{
RazorEngineHost host = CreateHost(designTime: designTime, isIndentingWithTabs: isIndentingWithTabs, tabSize: tabSize);
// no new lines involved
Span span = GenerateSpan(" @if (true)", SpanKind.Code, 2, "if (true)");
int generatedStart = 1;
string code = " if (true)";
int paddingCharCount;
string padded = CodeGeneratorPaddingHelper.PadStatement(host, code, span, ref generatedStart, out paddingCharCount);
VerifyPadded(numTabs, numSpaces, code, padded, paddingCharCount);
// with new lines involved
Span newLineSpan = GenerateSpan("\t<div>\r\n @if (true)", SpanKind.Code, 3, "if (true)");
string newLinePadded = CodeGeneratorPaddingHelper.PadStatement(host, code, span, ref generatedStart, out paddingCharCount);
VerifyPadded(numTabs, numSpaces, code, newLinePadded, paddingCharCount);
}
[Theory]
[InlineData(true, false, 4, 0, 8)]
[InlineData(true, false, 2, 0, 4)]
[InlineData(true, true, 4, 2, 0)]
[InlineData(true, true, 2, 2, 0)]
[InlineData(true, true, 1, 2, 0)]
[InlineData(true, true, 0, 2, 0)]
[InlineData(true, true, 3, 2, 0)]
// in non design time mode padding falls back to spaces to keep runtime code identical to v2 code.
[InlineData(false, true, 4, 0, 9)]
[InlineData(false, true, 2, 0, 5)]
[InlineData(false, false, 4, 0, 9)]
[InlineData(false, false, 2, 0, 5)]
public void VerifyPaddingForIfSpanWithTwoTabs(bool designTime, bool isIndentingWithTabs, int tabSize, int numTabs, int numSpaces)
{
RazorEngineHost host = CreateHost(designTime: designTime, isIndentingWithTabs: isIndentingWithTabs, tabSize: tabSize);
// no new lines involved
Span span = GenerateSpan("\t\t@if (true)", SpanKind.Code, 2, "if (true)");
int generatedStart = 1;
string code = " if (true)";
int paddingCharCount;
string padded = CodeGeneratorPaddingHelper.PadStatement(host, code, span, ref generatedStart, out paddingCharCount);
VerifyPadded(numTabs, numSpaces, code, padded, paddingCharCount);
// with new lines involved
Span newLineSpan = GenerateSpan("\t<div>\r\n\t\t@if (true)", SpanKind.Code, 3, "if (true)");
string newLinePadded = CodeGeneratorPaddingHelper.PadStatement(host, code, span, ref generatedStart, out paddingCharCount);
VerifyPadded(numTabs, numSpaces, code, newLinePadded, paddingCharCount);
}
[Theory]
[InlineData(true, false, 4, 0, 8)]
[InlineData(true, false, 2, 0, 4)]
[InlineData(true, true, 4, 2, 0)]
[InlineData(true, true, 2, 2, 0)]
[InlineData(true, true, 1, 2, 0)]
[InlineData(true, true, 0, 2, 0)]
// in non design time mode padding falls back to spaces to keep runtime code identical to v2 code.
[InlineData(false, true, 4, 0, 9)]
[InlineData(false, true, 2, 0, 5)]
[InlineData(false, false, 4, 0, 9)]
[InlineData(false, false, 2, 0, 5)]
public void CalculatePaddingForOpenedIf(bool designTime, bool isIndentingWithTabs, int tabSize, int numTabs, int numSpaces)
{
RazorEngineHost host = CreateHost(designTime: designTime, isIndentingWithTabs: isIndentingWithTabs, tabSize: tabSize);
string text = "\r\n<html>\r\n<body>\r\n\t\t@if (true) { \r\n</body>\r\n</html>";
Span span = GenerateSpan(text, SpanKind.Code, 3, "if (true) { \r\n");
int generatedStart = 1;
string code = " if (true) { \r\n";
int paddingCharCount;
string padded = CodeGeneratorPaddingHelper.PadStatement(host, code, span, ref generatedStart, out paddingCharCount);
VerifyPadded(numTabs, numSpaces, code, padded, paddingCharCount);
}
private static void VerifyPadded(int numTabs, int numSpaces, string code, string padded, int paddingCharCount)
{
Assert.Equal(numTabs + numSpaces + code.Length, padded.Length);
if (numTabs > 0 || numSpaces > 0)
{
Assert.True(padded.Length > numTabs + numSpaces, "padded string too short");
}
for (int i = 0; i < numTabs; i++)
{
Assert.Equal('\t', padded[i]);
}
for (int i = numTabs; i < numTabs + numSpaces; i++)
{
Assert.Equal(' ', padded[i]);
}
Assert.Equal(numSpaces + numTabs, paddingCharCount);
}
private static RazorEngineHost CreateHost(bool designTime, bool isIndentingWithTabs = false, int tabSize = 4)
{
return new RazorEngineHost(new CSharpRazorCodeLanguage())
{
DesignTimeMode = designTime,
IsIndentingWithTabs = isIndentingWithTabs,
TabSize = tabSize,
};
}
private static Span GenerateSpan(string text, SpanKind spanKind, int spanIndex, string spanText)
{
Span[] spans = GenerateSpans(text, spanKind, spanIndex, spanText);
return spans[spanIndex];
}
private static Span[] GenerateSpans(string text, SpanKind spanKind, int spanIndex, string spanText)
{
Assert.True(spanIndex > 0);
RazorParser parser = new RazorParser(new CSharpCodeParser(), new HtmlMarkupParser());
Span[] spans;
using (var reader = new StringReader(text))
{
ParserResults results = parser.Parse(reader);
spans = results.Document.Flatten().ToArray();
}
Assert.True(spans.Length > spanIndex);
Assert.Equal(spanKind, spans[spanIndex].Kind);
Assert.Equal(spanText, spans[spanIndex].Content);
return spans;
}
}
}

View File

@ -0,0 +1,245 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
//#define GENERATE_BASELINES
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using Microsoft.AspNet.Razor.Generator;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Test.Utils;
using System.Web.WebPages.TestUtils;
using Microsoft.TestCommon;
using System;
namespace Microsoft.AspNet.Razor.Test.Generator
{
public abstract class RazorCodeGeneratorTest<TLanguage>
where TLanguage : RazorCodeLanguage, new()
{
protected static readonly string TestRootNamespaceName = "TestOutput";
protected abstract string FileExtension { get; }
protected abstract string LanguageName { get; }
protected abstract string BaselineExtension { get; }
protected RazorEngineHost CreateHost()
{
return new RazorEngineHost(new TLanguage());
}
protected void RunTest(string name,
string baselineName = null,
bool generatePragmas = true,
bool designTimeMode = false,
IList<GeneratedCodeMapping> expectedDesignTimePragmas = null,
TestSpan[] spans = null,
TabTest tabTest = TabTest.Both,
Action<RazorEngineHost> hostConfig = null)
{
bool testRun = false;
if ((tabTest & TabTest.Tabs) == TabTest.Tabs)
{
// CodeDOM will inject its strings into the generated file header, so we force English.
using (new CultureReplacer())
{
RunTestInternal(
name: name,
baselineName: baselineName,
generatePragmas: generatePragmas,
designTimeMode: designTimeMode,
expectedDesignTimePragmas: expectedDesignTimePragmas,
spans: spans,
withTabs: true,
hostConfig: hostConfig);
}
testRun = true;
}
if ((tabTest & TabTest.NoTabs) == TabTest.NoTabs)
{
// CodeDOM will inject its strings into the generated file header, so we force English.
using (new CultureReplacer())
{
RunTestInternal(
name: name,
baselineName: baselineName,
generatePragmas: generatePragmas,
designTimeMode: designTimeMode,
expectedDesignTimePragmas: expectedDesignTimePragmas,
spans: spans,
withTabs: false,
hostConfig: hostConfig);
}
testRun = true;
}
Assert.True(testRun, "No test was run because TabTest is not set correctly");
}
private void RunTestInternal(string name,
string baselineName,
bool generatePragmas,
bool designTimeMode,
IList<GeneratedCodeMapping> expectedDesignTimePragmas,
TestSpan[] spans,
bool withTabs,
Action<RazorEngineHost> hostConfig)
{
// Load the test files
if (baselineName == null)
{
baselineName = name;
}
string source = TestFile.Create(String.Format("CodeGenerator.{1}.Source.{0}.{2}", name, LanguageName, FileExtension)).ReadAllText();
string expectedOutput = TestFile.Create(String.Format("CodeGenerator.{1}.Output.{0}.{2}", baselineName, LanguageName, BaselineExtension)).ReadAllText();
// Set up the host and engine
RazorEngineHost host = CreateHost();
host.NamespaceImports.Add("System");
host.DesignTimeMode = designTimeMode;
host.StaticHelpers = true;
host.DefaultClassName = name;
// Add support for templates, etc.
host.GeneratedClassContext = new GeneratedClassContext(GeneratedClassContext.DefaultExecuteMethodName,
GeneratedClassContext.DefaultWriteMethodName,
GeneratedClassContext.DefaultWriteLiteralMethodName,
"WriteTo",
"WriteLiteralTo",
"Template",
"DefineSection",
"BeginContext",
"EndContext")
{
LayoutPropertyName = "Layout",
ResolveUrlMethodName = "Href"
};
if (hostConfig != null)
{
hostConfig(host);
}
host.IsIndentingWithTabs = withTabs;
RazorTemplateEngine engine = new RazorTemplateEngine(host);
// Generate code for the file
GeneratorResults results = null;
using (StringTextBuffer buffer = new StringTextBuffer(source))
{
results = engine.GenerateCode(buffer, className: name, rootNamespace: TestRootNamespaceName, sourceFileName: generatePragmas ? String.Format("{0}.{1}", name, FileExtension) : null);
}
// Generate code
CodeCompileUnit ccu = results.GeneratedCode;
CodeDomProvider codeProvider = (CodeDomProvider)Activator.CreateInstance(host.CodeLanguage.CodeDomProviderType);
CodeGeneratorOptions options = new CodeGeneratorOptions();
// Both run-time and design-time use these settings. See:
// * $/Dev10/pu/SP_WebTools/venus/html/Razor/Impl/RazorCodeGenerator.cs:204
// * $/Dev10/Releases/RTMRel/ndp/fx/src/xsp/System/Web/Compilation/BuildManagerHost.cs:373
options.BlankLinesBetweenMembers = false;
options.IndentString = String.Empty;
StringBuilder output = new StringBuilder();
using (StringWriter writer = new StringWriter(output))
{
codeProvider.GenerateCodeFromCompileUnit(ccu, writer, options);
}
WriteBaseline(String.Format(@"test\Microsoft.AspNet.Razor.Test\TestFiles\CodeGenerator\{0}\Output\{1}.{2}", LanguageName, baselineName, BaselineExtension), MiscUtils.StripRuntimeVersion(output.ToString()));
#if !GENERATE_BASELINES
string textOutput = MiscUtils.StripRuntimeVersion(output.ToString());
//// Verify code against baseline
Assert.Equal(expectedOutput, textOutput);
#endif
IEnumerable<Span> generatedSpans = results.Document.Flatten();
foreach (var span in generatedSpans)
{
VerifyNoBrokenEndOfLines(span.Content);
}
// Verify design-time pragmas
if (designTimeMode)
{
if (spans != null)
{
Assert.Equal(spans, generatedSpans.Select(span => new TestSpan(span)).ToArray());
}
if (expectedDesignTimePragmas != null)
{
Assert.True(results.DesignTimeLineMappings != null && results.DesignTimeLineMappings.Count > 0);
Assert.Equal(expectedDesignTimePragmas.Count, results.DesignTimeLineMappings.Count);
Assert.Equal(
expectedDesignTimePragmas.ToArray(),
results.DesignTimeLineMappings
.OrderBy(p => p.Key)
.Select(p => p.Value)
.ToArray());
}
}
}
[Conditional("GENERATE_BASELINES")]
private void WriteBaseline(string baselineFile, string output)
{
string root = RecursiveFind("Runtime.sln", Path.GetFullPath("."));
string baselinePath = Path.Combine(root, baselineFile);
// Update baseline
// IMPORTANT! Replace this path with the local path on your machine to the baseline files!
if (File.Exists(baselinePath))
{
File.Delete(baselinePath);
}
File.WriteAllText(baselinePath, output.ToString());
}
private string RecursiveFind(string path, string start)
{
string test = Path.Combine(start, path);
if (File.Exists(test))
{
return start;
}
else
{
return RecursiveFind(path, new DirectoryInfo(start).Parent.FullName);
}
}
private void VerifyNoBrokenEndOfLines(string text)
{
for (int i = 0; i < text.Length; i++)
{
if (text[i] == '\r')
{
Assert.True(text.Length > i + 1);
Assert.Equal('\n', text[i + 1]);
}
else if (text[i] == '\n')
{
Assert.True(i > 0);
Assert.Equal('\r', text[i - 1]);
}
}
}
}
}

View File

@ -0,0 +1,13 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
namespace Microsoft.AspNet.Razor.Test.Generator
{
[Flags]
public enum TabTest
{
NoTabs = 1,
Tabs = 2,
Both = 3
}
}

View File

@ -0,0 +1,59 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.Diagnostics;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
namespace Microsoft.AspNet.Razor.Test.Generator
{
public class TestSpan
{
/// <summary>
/// Test span to simplify the generation of the actual Span in test initializer.
/// </summary>
/// <param name="kind">Span kind</param>
/// <param name="start">Zero indexed start char index in the buffer.</param>
/// <param name="end">End Column, if the text length is zero Start == End.</param>
public TestSpan(SpanKind kind, int start, int end)
{
Kind = kind;
Start = start;
End = end;
}
public TestSpan(Span span)
: this(span.Kind,
span.Start.AbsoluteIndex,
span.Start.AbsoluteIndex + span.Length)
{
}
public SpanKind Kind { get; private set; }
public int Start { get; private set; }
public int End { get; private set; }
public override string ToString()
{
return String.Format("{0}: {1}-{2}", Kind, Start, End);
}
public override bool Equals(object obj)
{
TestSpan other = obj as TestSpan;
if (other != null)
{
return (Kind == other.Kind) &&
(Start == other.Start) &&
(End == other.End);
}
return false;
}
public override int GetHashCode()
{
return base.GetHashCode();
}
}
}

View File

@ -0,0 +1,281 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using Microsoft.AspNet.Razor.Generator;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.Razor.Test.Generator
{
public class VBRazorCodeGeneratorTest : RazorCodeGeneratorTest<VBRazorCodeLanguage>
{
private const string TestPhysicalPath = @"C:\Bar.vbhtml";
private const string TestVirtualPath = "~/Foo/Bar.vbhtml";
protected override string FileExtension
{
get { return "vbhtml"; }
}
protected override string LanguageName
{
get { return "VB"; }
}
protected override string BaselineExtension
{
get { return "vb"; }
}
[Fact]
public void ConstructorRequiresNonNullClassName()
{
Assert.ThrowsArgumentNullOrEmptyString(() => new VBRazorCodeGenerator(null, TestRootNamespaceName, TestPhysicalPath, CreateHost()), "className");
}
[Fact]
public void ConstructorRequiresNonEmptyClassName()
{
Assert.ThrowsArgumentNullOrEmptyString(() => new VBRazorCodeGenerator(String.Empty, TestRootNamespaceName, TestPhysicalPath, CreateHost()), "className");
}
[Fact]
public void ConstructorRequiresNonNullRootNamespaceName()
{
Assert.ThrowsArgumentNull(() => new VBRazorCodeGenerator("Foo", null, TestPhysicalPath, CreateHost()), "rootNamespaceName");
}
[Fact]
public void ConstructorAllowsEmptyRootNamespaceName()
{
new VBRazorCodeGenerator("Foo", String.Empty, TestPhysicalPath, CreateHost());
}
[Fact]
public void ConstructorRequiresNonNullHost()
{
Assert.ThrowsArgumentNull(() => new VBRazorCodeGenerator("Foo", TestRootNamespaceName, TestPhysicalPath, null), "host");
}
[Theory]
[InlineData("NestedCodeBlocks")]
[InlineData("NestedCodeBlocks")]
[InlineData("CodeBlock")]
[InlineData("ExplicitExpression")]
[InlineData("MarkupInCodeBlock")]
[InlineData("Blocks")]
[InlineData("ImplicitExpression")]
[InlineData("Imports")]
[InlineData("ExpressionsInCode")]
[InlineData("FunctionsBlock")]
[InlineData("Options")]
[InlineData("Templates")]
[InlineData("RazorComments")]
[InlineData("Sections")]
[InlineData("EmptySection")] // this scenario causes a crash in Razor V2.0
[InlineData("Helpers")]
[InlineData("HelpersMissingCloseParen")]
[InlineData("HelpersMissingOpenParen")]
[InlineData("NestedHelpers")]
[InlineData("LayoutDirective")]
[InlineData("ConditionalAttributes")]
[InlineData("ResolveUrl")]
public void VBCodeGeneratorCorrectlyGeneratesRunTimeCode(string testName)
{
RunTest(testName);
}
[Fact]
public void VBCodeGeneratorCorrectlyGeneratesMappingsForRazorCommentsAtDesignTime()
{
// (4, 6) -> (?, 6) [6]
// ( 5, 40) -> (?, 39) [2]
// ( 8, 6) -> (?, 6) [33]
// ( 9, 46) -> (?, 46) [3]
// ( 12, 3) -> (?, 7) [3]
// ( 12, 8) -> (?, 8) [1]
RunTest("RazorComments", "RazorComments.DesignTime", designTimeMode: true, tabTest: TabTest.NoTabs, expectedDesignTimePragmas: new List<GeneratedCodeMapping>()
{
/* 01 */ new GeneratedCodeMapping(4, 6, 6, 6),
/* 02 */ new GeneratedCodeMapping(5, 40, 39, 2),
/* 03 */ new GeneratedCodeMapping(8, 6, 6, 33),
/* 04 */ new GeneratedCodeMapping(9, 46, 46, 3),
/* 05 */ new GeneratedCodeMapping(12, 3, 7, 1),
/* 06 */ new GeneratedCodeMapping(12, 8, 8, 1)
});
}
[Fact]
public void VBCodeGeneratorCorrectlyGeneratesHelperMissingNameAtDesignTime()
{
RunTest("HelpersMissingName", designTimeMode: true);
}
[Fact]
public void VBCodeGeneratorCorrectlyGeneratesImportStatementsAtDesignTimeButCannotWrapPragmasAroundImportStatement()
{
RunTest("Imports", "Imports.DesignTime", designTimeMode: true, tabTest: TabTest.NoTabs, expectedDesignTimePragmas: new List<GeneratedCodeMapping>()
{
/* 01 */ new GeneratedCodeMapping(1, 2, 1, 19),
/* 02 */ new GeneratedCodeMapping(2, 2, 1, 36),
/* 03 */ new GeneratedCodeMapping(3, 2, 1, 16),
/* 04 */ new GeneratedCodeMapping(5, 30, 30, 22),
/* 05 */ new GeneratedCodeMapping(6, 36, 36, 21),
});
}
[Fact]
public void VBCodeGeneratorCorrectlyGeneratesFunctionsBlocksAtDesignTime()
{
RunTest("FunctionsBlock", "FunctionsBlock.DesignTime", designTimeMode: true, tabTest: TabTest.NoTabs, expectedDesignTimePragmas: new List<GeneratedCodeMapping>()
{
/* 01 */ new GeneratedCodeMapping(1, 11, 11, 4),
/* 02 */ new GeneratedCodeMapping(5, 11, 11, 129),
/* 03 */ new GeneratedCodeMapping(12, 26, 26, 11)
});
}
[Fact]
public void VBCodeGeneratorCorrectlyGeneratesFunctionsBlocksAtDesignTimeTabs()
{
RunTest("FunctionsBlock", "FunctionsBlock.DesignTime.Tabs", designTimeMode: true, tabTest: TabTest.Tabs, expectedDesignTimePragmas: new List<GeneratedCodeMapping>()
{
/* 01 */ new GeneratedCodeMapping(1, 11, 5, 4),
/* 02 */ new GeneratedCodeMapping(5, 11, 5, 129),
/* 03 */ new GeneratedCodeMapping(12, 26, 14, 11)
});
}
[Fact]
public void VBCodeGeneratorGeneratesCodeWithParserErrorsInDesignTimeMode()
{
RunTest("ParserError", designTimeMode: true, tabTest: TabTest.NoTabs, expectedDesignTimePragmas: new List<GeneratedCodeMapping>()
{
/* 01 */ new GeneratedCodeMapping(1, 6, 6, 16)
});
}
[Fact]
public void VBCodeGeneratorCorrectlyGeneratesInheritsAtRuntime()
{
RunTest("Inherits", baselineName: "Inherits.Runtime");
}
[Fact]
public void VBCodeGeneratorCorrectlyGeneratesInheritsAtDesigntime()
{
RunTest("Inherits", baselineName: "Inherits.Designtime", designTimeMode: true, expectedDesignTimePragmas: new List<GeneratedCodeMapping>()
{
/* 01 */ new GeneratedCodeMapping(1, 11, 25, 27)
});
}
[Fact]
public void VBCodeGeneratorCorrectlyGeneratesDesignTimePragmasForUnfinishedExpressionsInCode()
{
RunTest("UnfinishedExpressionInCode", designTimeMode: true, tabTest: TabTest.NoTabs, expectedDesignTimePragmas: new List<GeneratedCodeMapping>()
{
/* 01 */ new GeneratedCodeMapping(1, 6, 6, 2),
/* 02 */ new GeneratedCodeMapping(2, 2, 7, 9),
/* 03 */ new GeneratedCodeMapping(2, 11, 11, 2)
});
}
[Fact]
public void VBCodeGeneratorCorrectlyGeneratesDesignTimePragmasMarkupAndExpressions()
{
RunTest("DesignTime", designTimeMode: true, tabTest: TabTest.NoTabs, expectedDesignTimePragmas: new List<GeneratedCodeMapping>()
{
/* 01 */ new GeneratedCodeMapping(2, 14, 13, 17),
/* 02 */ new GeneratedCodeMapping(3, 20, 20, 1),
/* 03 */ new GeneratedCodeMapping(3, 25, 25, 20),
/* 04 */ new GeneratedCodeMapping(8, 3, 7, 12),
/* 05 */ new GeneratedCodeMapping(9, 2, 7, 4),
/* 06 */ new GeneratedCodeMapping(9, 16, 16, 3),
/* 07 */ new GeneratedCodeMapping(9, 27, 27, 1),
/* 08 */ new GeneratedCodeMapping(14, 6, 7, 3),
/* 09 */ new GeneratedCodeMapping(17, 9, 24, 5),
/* 10 */ new GeneratedCodeMapping(17, 14, 14, 28),
/* 11 */ new GeneratedCodeMapping(19, 20, 20, 14)
});
}
[Fact]
public void VBCodeGeneratorCorrectlyGeneratesDesignTimePragmasForImplicitExpressionStartedAtEOF()
{
RunTest("ImplicitExpressionAtEOF", designTimeMode: true, expectedDesignTimePragmas: new List<GeneratedCodeMapping>()
{
/* 01 */ new GeneratedCodeMapping(3, 2, 7, 0)
});
}
[Fact]
public void VBCodeGeneratorCorrectlyGeneratesDesignTimePragmasForExplicitExpressionStartedAtEOF()
{
RunTest("ExplicitExpressionAtEOF", designTimeMode: true, expectedDesignTimePragmas: new List<GeneratedCodeMapping>()
{
/* 01 */ new GeneratedCodeMapping(3, 3, 7, 0)
});
}
[Fact]
public void VBCodeGeneratorCorrectlyGeneratesDesignTimePragmasForCodeBlockStartedAtEOF()
{
RunTest("CodeBlockAtEOF", designTimeMode: true, tabTest: TabTest.NoTabs, expectedDesignTimePragmas: new List<GeneratedCodeMapping>()
{
/* 01 */ new GeneratedCodeMapping(3, 6, 6, 0)
});
}
[Fact]
public void VBCodeGeneratorCorrectlyGeneratesDesignTimePragmasForEmptyImplicitExpression()
{
RunTest("EmptyImplicitExpression", designTimeMode: true, expectedDesignTimePragmas: new List<GeneratedCodeMapping>()
{
/* 01 */ new GeneratedCodeMapping(3, 2, 7, 0)
});
}
[Fact]
public void VBCodeGeneratorCorrectlyGeneratesDesignTimePragmasForEmptyImplicitExpressionInCode()
{
RunTest("EmptyImplicitExpressionInCode", designTimeMode: true, tabTest: TabTest.NoTabs, expectedDesignTimePragmas: new List<GeneratedCodeMapping>()
{
/* 01 */ new GeneratedCodeMapping(1, 6, 6, 6),
/* 02 */ new GeneratedCodeMapping(2, 6, 7, 0),
/* 03 */ new GeneratedCodeMapping(2, 6, 6, 2)
});
}
[Fact]
public void VBCodeGeneratorCorrectlyGeneratesDesignTimePragmasForEmptyExplicitExpression()
{
RunTest("EmptyExplicitExpression", designTimeMode: true, expectedDesignTimePragmas: new List<GeneratedCodeMapping>()
{
/* 01 */ new GeneratedCodeMapping(3, 3, 7, 0)
});
}
[Fact]
public void VBCodeGeneratorDoesNotRenderLinePragmasIfGenerateLinePragmasIsSetToFalse()
{
RunTest("NoLinePragmas", generatePragmas: false);
}
[Fact]
public void VBCodeGeneratorRendersHelpersBlockCorrectlyWhenInstanceHelperRequested()
{
RunTest("Helpers", baselineName: "Helpers.Instance", hostConfig: h => h.StaticHelpers = false);
}
[Fact]
public void VBCodeGeneratorCorrectlyInstrumentsRazorCodeWhenInstrumentationRequested()
{
RunTest("Instrumented", hostConfig: host =>
{
host.EnableInstrumentation = true;
host.InstrumentedSourceFilePath = String.Format("~/{0}.vbhtml", host.DefaultClassName);
});
}
}
}

View File

@ -0,0 +1,468 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{0BB62A1D-E6B5-49FA-9E3C-6AF679A66DFE}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Microsoft.AspNet.Razor.Test</RootNamespace>
<AssemblyName>Microsoft.AspNet.Razor.Test</AssemblyName>
<OutputPath>..\..\bin\$(Configuration)\Test\</OutputPath>
<NoWarn>0618</NoWarn>
<TargetFrameworkVersion>v4.5.1</TargetFrameworkVersion>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Debug'">
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.CSharp" />
<Reference Include="Moq, Version=4.0.10827.0, Culture=neutral, PublicKeyToken=69f491c39445e920, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\packages\Moq.4.0.10827\lib\NET40\Moq.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="xunit, Version=1.9.1.1600, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\packages\xunit.1.9.1\lib\net20\xunit.dll</HintPath>
<Aliases>unused</Aliases>
</Reference>
<Reference Include="xunit.extensions, Version=1.9.1.1600, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\packages\xunit.extensions.1.9.1\lib\net20\xunit.extensions.dll</HintPath>
<Aliases>unused</Aliases>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="CodeCompileUnitExtensions.cs" />
<Compile Include="Framework\BlockExtensions.cs" />
<Compile Include="Framework\BlockTypes.cs" />
<Compile Include="Framework\CodeParserTestBase.cs" />
<Compile Include="Framework\CsHtmlCodeParserTestBase.cs" />
<Compile Include="Framework\CsHtmlMarkupParserTestBase.cs" />
<Compile Include="Framework\ErrorCollector.cs" />
<Compile Include="Framework\MarkupParserTestBase.cs" />
<Compile Include="Framework\ParserTestBase.cs" />
<Compile Include="Framework\RawTextSymbol.cs" />
<Compile Include="Framework\TestSpanBuilder.cs" />
<Compile Include="Framework\VBHtmlCodeParserTestBase.cs" />
<Compile Include="Framework\VBHtmlMarkupParserTestBase.cs" />
<Compile Include="Generator\GeneratedCodeMappingTest.cs" />
<Compile Include="Generator\PaddingTest.cs" />
<Compile Include="Generator\TabTest.cs" />
<Compile Include="Generator\TestSpan.cs" />
<Compile Include="Parser\CSharp\CSharpAutoCompleteTest.cs" />
<Compile Include="Parser\CSharp\CSharpDirectivesTest.cs" />
<Compile Include="Parser\CSharp\CSharpLayoutDirectiveTest.cs" />
<Compile Include="Parser\CSharp\CSharpNestedStatementsTest.cs" />
<Compile Include="Parser\CSharp\CSharpRazorCommentsTest.cs" />
<Compile Include="Parser\CSharp\CSharpStatementTest.cs" />
<Compile Include="Parser\CSharp\CSharpTemplateTest.cs" />
<Compile Include="Parser\CSharp\CSharpToMarkupSwitchTest.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Parser\CSharp\CSharpVerbatimBlockTest.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Parser\CSharp\CSharpWhitespaceHandlingTest.cs" />
<Compile Include="Parser\CSharp\CsHtmlDocumentTest.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Parser\Html\HtmlAttributeTest.cs" />
<Compile Include="Parser\Html\HtmlUrlAttributeTest.cs" />
<Compile Include="Parser\ParserVisitorExtensionsTest.cs" />
<Compile Include="Parser\VB\VBRazorCommentsTest.cs" />
<Compile Include="Parser\VB\VBLayoutDirectiveTest.cs" />
<Compile Include="Parser\VB\VBAutoCompleteTest.cs" />
<Compile Include="Parser\Html\HtmlTagsTest.cs" />
<Compile Include="Parser\VB\VBContinueStatementTest.cs" />
<Compile Include="Parser\VB\VBDirectiveTest.cs" />
<Compile Include="Parser\VB\VBExitStatementTest.cs" />
<Compile Include="Parser\VB\VBExplicitExpressionTest.cs" />
<Compile Include="Parser\VB\VBImplicitExpressionTest.cs" />
<Compile Include="Parser\VB\VBReservedWordsTest.cs" />
<Compile Include="Parser\CSharp\CSharpReservedWordsTest.cs" />
<Compile Include="Parser\PartialParsing\VBPartialParsingTest.cs" />
<Compile Include="Parser\PartialParsing\CSharpPartialParsingTest.cs" />
<Compile Include="Parser\VB\VBHelperTest.cs" />
<Compile Include="Parser\CSharp\CSharpHelperTest.cs" />
<Compile Include="Generator\RazorCodeGeneratorTest.cs" />
<Compile Include="Parser\PartialParsing\PartialParsingTestBase.cs" />
<Compile Include="Parser\VB\VBNestedStatementsTest.cs" />
<Compile Include="Parser\VB\VBStatementTest.cs" />
<Compile Include="Parser\WhitespaceRewriterTest.cs" />
<Compile Include="RazorCodeLanguageTest.cs" />
<Compile Include="Parser\VB\VBHtmlDocumentTest.cs" />
<Compile Include="Parser\VB\VBErrorTest.cs" />
<Compile Include="Parser\VB\VBSectionTest.cs" />
<Compile Include="Parser\VB\VBTemplateTest.cs" />
<Compile Include="Parser\VB\VBExpressionsInCodeTest.cs" />
<Compile Include="Parser\VB\VBSpecialKeywordsTest.cs" />
<Compile Include="Parser\VB\VBBlockTest.cs" />
<Compile Include="Parser\VB\VBToMarkupSwitchTest.cs" />
<Compile Include="Editor\RazorEditorParserTest.cs" />
<Compile Include="RazorDirectiveAttributeTest.cs" />
<Compile Include="RazorEngineHostTest.cs" />
<Compile Include="RazorTemplateEngineTest.cs" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Output\Blocks.cs" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Output\CodeBlock.cs" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Output\CodeBlockAtEOF.cs" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Output\Comments.cs" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Output\ConditionalAttributes.cs" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Output\DesignTime.cs" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Output\EmptyCodeBlock.cs" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Output\EmptyExplicitExpression.cs" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Output\EmptyImplicitExpression.cs" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Output\EmptyImplicitExpressionInCode.cs" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Output\ExplicitExpression.cs" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Output\ExplicitExpressionAtEOF.cs" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Output\ExpressionsInCode.cs" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Output\FunctionsBlock.cs" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Output\FunctionsBlock.DesignTime.cs" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Output\Helpers.cs" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Output\Helpers.Instance.cs" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Output\HelpersMissingCloseParen.cs" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Output\HelpersMissingName.cs" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Output\HelpersMissingOpenBrace.cs" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Output\HelpersMissingOpenParen.cs" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Output\HiddenSpansInCode.cs" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Output\ImplicitExpression.cs" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Output\ImplicitExpressionAtEOF.cs" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Output\Imports.cs" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Output\Imports.DesignTime.cs" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Output\Inherits.Designtime.cs" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Output\Inherits.Runtime.cs" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Output\InlineBlocks.cs" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Output\Instrumented.cs" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Output\LayoutDirective.cs" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Output\MarkupInCodeBlock.cs" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Output\NestedCodeBlocks.cs" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Output\NestedHelpers.cs" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Output\NoLinePragmas.cs" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Output\ParserError.cs" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Output\RazorComments.cs" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Output\ResolveUrl.cs" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Output\Sections.cs" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Output\Templates.cs" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Output\UnfinishedExpressionInCode.cs" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Output\RazorComments.DesignTime.cs" />
<Compile Include="StringTextBuffer.cs" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Output\OpenedIf.DesignTime.cs" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Output\OpenedIf.DesignTime.Tabs.cs" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Output\UnfinishedExpressionInCode.Tabs.cs" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Output\EmptyImplicitExpressionInCode.Tabs.cs" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Output\DesignTime.Tabs.cs" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Output\FunctionsBlock.DesignTime.Tabs.cs" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Output\FunctionsBlock_Tabs.cs" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Output\FunctionsBlockMinimal.DesignTime.Tabs.cs" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Output\SimpleUnspacedIf.DesignTime.Tabs.cs" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Output\HtmlCommentWithQuote_Single.cs" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Output\HtmlCommentWithQuote_Double.cs" />
<Compile Include="Text\LineTrackingStringBufferTest.cs" />
<Compile Include="Tokenizer\VBTokenizerLiteralTest.cs" />
<Compile Include="Tokenizer\VBTokenizerIdentifierTest.cs" />
<Compile Include="Tokenizer\VBTokenizerCommentTest.cs" />
<Compile Include="Tokenizer\VBTokenizerOperatorsTest.cs" />
<Compile Include="Tokenizer\VBTokenizerTestBase.cs" />
<Compile Include="Tokenizer\VBTokenizerTest.cs" />
<Compile Include="Tokenizer\CSharpTokenizerCommentTest.cs" />
<Compile Include="Tokenizer\CSharpTokenizerLiteralTest.cs" />
<Compile Include="Tokenizer\CSharpTokenizerIdentifierTest.cs" />
<Compile Include="Tokenizer\CSharpTokenizerOperatorsTest.cs" />
<Compile Include="Tokenizer\CSharpTokenizerTestBase.cs" />
<Compile Include="Tokenizer\CSharpTokenizerTest.cs" />
<Compile Include="Tokenizer\TokenizerLookaheadTest.cs" />
<Compile Include="Tokenizer\HtmlTokenizerTest.cs" />
<Compile Include="Tokenizer\HtmlTokenizerTestBase.cs" />
<Compile Include="Tokenizer\TokenizerTestBase.cs" />
<Compile Include="Utils\MiscUtils.cs" />
<Compile Include="Generator\VBRazorCodeGeneratorTest.cs" />
<Compile Include="Generator\CSharpRazorCodeGeneratorTest.cs" />
<Compile Include="CSharpRazorCodeLanguageTest.cs" />
<Compile Include="Parser\CallbackParserListenerTest.cs" />
<Compile Include="Parser\CSharp\CSharpExplicitExpressionTest.cs" />
<Compile Include="Parser\CSharp\CSharpSectionTest.cs" />
<Compile Include="Parser\BlockTest.cs" />
<Compile Include="Parser\VB\VBExpressionTest.cs" />
<Compile Include="Text\BufferingTextReaderTest.cs" />
<Compile Include="Parser\CSharp\CSharpErrorTest.cs" />
<Compile Include="Parser\CSharp\CSharpImplicitExpressionTest.cs" />
<Compile Include="Parser\CSharp\CSharpSpecialBlockTest.cs" />
<Compile Include="Parser\Html\HtmlBlockTest.cs" />
<Compile Include="Parser\CSharp\CSharpBlockTest.cs" />
<Compile Include="Text\LookaheadTextReaderTestBase.cs" />
<Compile Include="Text\SourceLocationTrackerTest.cs" />
<Compile Include="Text\TextBufferReaderTest.cs" />
<Compile Include="Utils\DisposableActionTest.cs" />
<Compile Include="Parser\Html\HtmlDocumentTest.cs" />
<Compile Include="Parser\ParserContextTest.cs" />
<Compile Include="Parser\Html\HtmlErrorTest.cs" />
<Compile Include="Parser\Html\HtmlParserTestUtils.cs" />
<Compile Include="Parser\Html\HtmlToCodeSwitchTest.cs" />
<Compile Include="Parser\RazorParserTest.cs" />
<Compile Include="Text\SourceLocationTest.cs" />
<Compile Include="Utils\SpanAssert.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="VBRazorCodeLanguageTest.cs" />
<Compile Include="Text\TextChangeTest.cs" />
<Compile Include="Text\TextReaderExtensionsTest.cs" />
<Compile Include="Utils\EnumerableUtils.cs" />
<Compile Include="Utils\MiscAssert.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Microsoft.AspNet.Razor\Microsoft.AspNet.Razor.csproj">
<Project>{e75d8296-3ba6-4e67-afeb-90ff77460b15}</Project>
<Name>Microsoft.AspNet.Razor</Name>
</ProjectReference>
<ProjectReference Include="..\Microsoft.TestCommon\Microsoft.TestCommon.csproj">
<Project>{FCCC4CB7-BAF7-4A57-9F89-E5766FE536C0}</Project>
<Name>Microsoft.TestCommon</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TestFiles\nested-1000.html" />
</ItemGroup>
<ItemGroup>
<Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Source\CodeBlock.vbhtml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Source\ExplicitExpression.vbhtml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Source\MarkupInCodeBlock.vbhtml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Source\Blocks.vbhtml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Source\ImplicitExpression.vbhtml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Source\NoLinePragmas.vbhtml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Source\Imports.vbhtml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Source\ExpressionsInCode.vbhtml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Source\FunctionsBlock.vbhtml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Source\Options.vbhtml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Source\Templates.vbhtml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Source\Sections.vbhtml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Source\DesignTime.vbhtml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Source\Templates.cshtml" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Source\Blocks.cshtml" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Source\CodeBlock.cshtml" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Source\NoLinePragmas.cshtml" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Source\ExplicitExpression.cshtml" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Source\ImplicitExpression.cshtml" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Source\Imports.cshtml" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Source\MarkupInCodeBlock.cshtml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Source\DesignTime.cshtml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Source\ExpressionsInCode.cshtml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Source\FunctionsBlock.cshtml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Source\Sections.cshtml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Source\Inherits.cshtml" />
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Source\Inherits.vbhtml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Source\NestedHelpers.cshtml" />
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Source\NestedHelpers.vbhtml" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Source\Instrumented.cshtml" />
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Source\Instrumented.vbhtml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Source\RazorComments.cshtml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Source\RazorComments.vbhtml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Source\ParserError.cshtml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Source\ParserError.vbhtml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Source\ImplicitExpressionAtEOF.cshtml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Source\CodeBlockAtEOF.cshtml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Source\ExplicitExpressionAtEOF.cshtml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Source\EmptyCodeBlock.cshtml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Source\EmptyExplicitExpression.cshtml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Source\EmptyImplicitExpression.cshtml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Source\CodeBlockAtEOF.vbhtml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Source\EmptyExplicitExpression.vbhtml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Source\EmptyImplicitExpression.vbhtml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Source\ExplicitExpressionAtEOF.vbhtml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Source\ImplicitExpressionAtEOF.vbhtml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Source\UnfinishedExpressionInCode.cshtml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Source\UnfinishedExpressionInCode.vbhtml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TestFiles\DesignTime\Simple.cshtml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TestFiles\DesignTime\Simple.txt" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Source\Helpers.cshtml" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Source\HelpersMissingCloseParen.cshtml" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Source\HelpersMissingName.cshtml" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Source\HelpersMissingOpenBrace.cshtml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Source\HelpersMissingOpenParen.cshtml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Source\HelpersMissingOpenParen.vbhtml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Source\Helpers.vbhtml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Source\HelpersMissingCloseParen.vbhtml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Source\HelpersMissingName.vbhtml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Source\NestedCodeBlocks.cshtml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Source\NestedCodeBlocks.vbhtml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Source\InlineBlocks.cshtml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Source\EmptyImplicitExpressionInCode.cshtml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Source\EmptyImplicitExpressionInCode.vbhtml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Source\HiddenSpansInCode.cshtml" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Source\ResolveUrl.cshtml" />
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Source\ResolveUrl.vbhtml" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Source\LayoutDirective.cshtml" />
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Source\LayoutDirective.vbhtml" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Source\ConditionalAttributes.cshtml" />
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Source\ConditionalAttributes.vbhtml" />
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Source\EmptySection.vbhtml" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Source\OpenedIf.cshtml" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Source\FunctionsBlock_Tabs.cshtml" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Source\FunctionsBlockMinimal.cshtml" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Source\SimpleUnspacedIf.cshtml" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Source\HtmlCommentWithQuote_Double.cshtml" />
<EmbeddedResource Include="TestFiles\CodeGenerator\CS\Source\HtmlCommentWithQuote_Single.cshtml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Output\Blocks.vb" />
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Output\CodeBlock.vb" />
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Output\CodeBlockAtEOF.vb" />
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Output\Comments.vb" />
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Output\ConditionalAttributes.vb" />
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Output\DesignTime.vb" />
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Output\EmptyExplicitExpression.vb" />
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Output\EmptyImplicitExpression.vb" />
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Output\EmptyImplicitExpressionInCode.vb" />
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Output\ExplicitExpression.vb" />
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Output\ExplicitExpressionAtEOF.vb" />
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Output\ExpressionsInCode.vb" />
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Output\FunctionsBlock.DesignTime.vb" />
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Output\FunctionsBlock.vb" />
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Output\Helpers.Instance.vb" />
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Output\Helpers.vb" />
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Output\HelpersMissingCloseParen.vb" />
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Output\HelpersMissingName.vb" />
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Output\HelpersMissingOpenParen.vb" />
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Output\ImplicitExpression.vb" />
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Output\ImplicitExpressionAtEOF.vb" />
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Output\Imports.DesignTime.vb" />
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Output\Imports.vb" />
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Output\Inherits.Designtime.vb" />
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Output\Inherits.Runtime.vb" />
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Output\Instrumented.vb" />
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Output\LayoutDirective.vb" />
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Output\MarkupInCodeBlock.vb" />
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Output\NestedCodeBlocks.vb" />
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Output\NestedHelpers.vb" />
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Output\NoLinePragmas.vb" />
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Output\Options.vb" />
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Output\ParserError.vb" />
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Output\RazorComments.vb" />
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Output\ResolveUrl.vb" />
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Output\Sections.vb" />
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Output\Templates.vb" />
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Output\UnfinishedExpressionInCode.vb" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Output\RazorComments.DesignTime.vb" />
</ItemGroup>
<ItemGroup>
<Folder Include="Properties\" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Output\EmptySection.vb" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TestFiles\CodeGenerator\VB\Output\FunctionsBlock.DesignTime.Tabs.vb" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project>

View File

@ -0,0 +1,124 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System.Linq;
using Microsoft.AspNet.Razor.Generator;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.AspNet.Razor.Text;
using System.Web.WebPages.TestUtils;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.Razor.Test.Parser
{
public class BlockTest
{
[Fact]
public void ConstructorWithBlockBuilderSetsParent()
{
// Arrange
BlockBuilder builder = new BlockBuilder() { Type = BlockType.Comment };
Span span = new SpanBuilder() { Kind = SpanKind.Code }.Build();
builder.Children.Add(span);
// Act
Block block = builder.Build();
// Assert
Assert.Same(block, span.Parent);
}
[Fact]
public void ConstructorCopiesBasicValuesFromBlockBuilder()
{
// Arrange
BlockBuilder builder = new BlockBuilder()
{
Name = "Foo",
Type = BlockType.Helper
};
// Act
Block actual = builder.Build();
// Assert
Assert.Equal("Foo", actual.Name);
Assert.Equal(BlockType.Helper, actual.Type);
}
[Fact]
public void ConstructorTransfersInstanceOfCodeGeneratorFromBlockBuilder()
{
// Arrange
IBlockCodeGenerator expected = new ExpressionCodeGenerator();
BlockBuilder builder = new BlockBuilder()
{
Type = BlockType.Helper,
CodeGenerator = expected
};
// Act
Block actual = builder.Build();
// Assert
Assert.Same(expected, actual.CodeGenerator);
}
[Fact]
public void ConstructorTransfersChildrenFromBlockBuilder()
{
// Arrange
Span expected = new SpanBuilder() { Kind = SpanKind.Code }.Build();
BlockBuilder builder = new BlockBuilder()
{
Type = BlockType.Functions
};
builder.Children.Add(expected);
// Act
Block block = builder.Build();
// Assert
Assert.Same(expected, block.Children.Single());
}
[Fact]
public void LocateOwnerReturnsNullIfNoSpanReturnsTrueForOwnsSpan()
{
// Arrange
var factory = SpanFactory.CreateCsHtml();
Block block = new MarkupBlock(
factory.Markup("Foo "),
new StatementBlock(
factory.CodeTransition(),
factory.Code("bar").AsStatement()),
factory.Markup(" Baz"));
TextChange change = new TextChange(128, 1, new StringTextBuffer("Foo @bar Baz"), 1, new StringTextBuffer("Foo @bor Baz"));
// Act
Span actual = block.LocateOwner(change);
// Assert
Assert.Null(actual);
}
[Fact]
public void LocateOwnerReturnsNullIfChangeCrossesMultipleSpans()
{
// Arrange
var factory = SpanFactory.CreateCsHtml();
Block block = new MarkupBlock(
factory.Markup("Foo "),
new StatementBlock(
factory.CodeTransition(),
factory.Code("bar").AsStatement()),
factory.Markup(" Baz"));
TextChange change = new TextChange(4, 10, new StringTextBuffer("Foo @bar Baz"), 10, new StringTextBuffer("Foo @bor Baz"));
// Act
Span actual = block.LocateOwner(change);
// Assert
Assert.Null(actual);
}
}
}

View File

@ -0,0 +1,175 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.Razor.Generator;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Resources;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.AspNet.Razor.Text;
using Microsoft.AspNet.Razor.Tokenizer.Symbols;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
{
public class CSharpAutoCompleteTest : CsHtmlCodeParserTestBase
{
[Fact]
public void FunctionsDirectiveAutoCompleteAtEOF()
{
ParseBlockTest("@functions{",
new FunctionsBlock(
Factory.CodeTransition("@")
.Accepts(AcceptedCharacters.None),
Factory.MetaCode("functions{")
.Accepts(AcceptedCharacters.None),
Factory.EmptyCSharp()
.AsFunctionsBody()
.With(new AutoCompleteEditHandler(CSharpLanguageCharacteristics.Instance.TokenizeString)
{
AutoCompleteString = "}"
})),
new RazorError(String.Format(RazorResources.ParseError_Expected_EndOfBlock_Before_EOF, "functions", "}", "{"),
1, 0, 1));
}
[Fact]
public void HelperDirectiveAutoCompleteAtEOF()
{
ParseBlockTest("@helper Strong(string value) {",
new HelperBlock(new HelperCodeGenerator(new LocationTagged<string>("Strong(string value) {", 8, 0, 8), headerComplete: true),
Factory.CodeTransition(),
Factory.MetaCode("helper ")
.Accepts(AcceptedCharacters.None),
Factory.Code("Strong(string value) {")
.Hidden()
.Accepts(AcceptedCharacters.None),
new StatementBlock(
Factory.EmptyCSharp()
.AsStatement()
.With(new AutoCompleteEditHandler(CSharpLanguageCharacteristics.Instance.TokenizeString) { AutoCompleteString = "}" })
)
),
new RazorError(String.Format(RazorResources.ParseError_Expected_EndOfBlock_Before_EOF, "helper", "}", "{"),
1, 0, 1));
}
[Fact]
public void SectionDirectiveAutoCompleteAtEOF()
{
ParseBlockTest("@section Header {",
new SectionBlock(new SectionCodeGenerator("Header"),
Factory.CodeTransition(),
Factory.MetaCode("section Header {")
.AutoCompleteWith("}", atEndOfSpan: true)
.Accepts(AcceptedCharacters.Any),
new MarkupBlock()),
new RazorError(
String.Format(RazorResources.ParseError_Expected_X, "}"),
17, 0, 17));
}
[Fact]
public void VerbatimBlockAutoCompleteAtEOF()
{
ParseBlockTest("@{",
new StatementBlock(
Factory.CodeTransition(),
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.EmptyCSharp()
.AsStatement()
.With(new AutoCompleteEditHandler(CSharpLanguageCharacteristics.Instance.TokenizeString) { AutoCompleteString = "}" })
),
new RazorError(String.Format(RazorResources.ParseError_Expected_EndOfBlock_Before_EOF, RazorResources.BlockName_Code, "}", "{"),
1, 0, 1));
}
[Fact]
public void FunctionsDirectiveAutoCompleteAtStartOfFile()
{
ParseBlockTest("@functions{" + Environment.NewLine
+ "foo",
new FunctionsBlock(
Factory.CodeTransition("@")
.Accepts(AcceptedCharacters.None),
Factory.MetaCode("functions{")
.Accepts(AcceptedCharacters.None),
Factory.Code("\r\nfoo")
.AsFunctionsBody()
.With(new AutoCompleteEditHandler(CSharpLanguageCharacteristics.Instance.TokenizeString)
{
AutoCompleteString = "}"
})),
new RazorError(String.Format(RazorResources.ParseError_Expected_EndOfBlock_Before_EOF, "functions", "}", "{"),
1, 0, 1));
}
[Fact]
public void HelperDirectiveAutoCompleteAtStartOfFile()
{
ParseBlockTest("@helper Strong(string value) {" + Environment.NewLine
+ "<p></p>",
new HelperBlock(new HelperCodeGenerator(new LocationTagged<string>("Strong(string value) {", 8, 0, 8), headerComplete: true),
Factory.CodeTransition(),
Factory.MetaCode("helper ")
.Accepts(AcceptedCharacters.None),
Factory.Code("Strong(string value) {")
.Hidden()
.Accepts(AcceptedCharacters.None),
new StatementBlock(
Factory.Code("\r\n")
.AsStatement()
.With(new AutoCompleteEditHandler(CSharpLanguageCharacteristics.Instance.TokenizeString) { AutoCompleteString = "}" }),
new MarkupBlock(
Factory.Markup(@"<p></p>")
.With(new MarkupCodeGenerator())
.Accepts(AcceptedCharacters.None)
),
Factory.Span(SpanKind.Code, new CSharpSymbol(Factory.LocationTracker.CurrentLocation, String.Empty, CSharpSymbolType.Unknown))
.With(new StatementCodeGenerator())
)
),
new RazorError(String.Format(RazorResources.ParseError_Expected_EndOfBlock_Before_EOF, "helper", "}", "{"),
1, 0, 1));
}
[Fact]
public void SectionDirectiveAutoCompleteAtStartOfFile()
{
ParseBlockTest("@section Header {" + Environment.NewLine
+ "<p>Foo</p>",
new SectionBlock(new SectionCodeGenerator("Header"),
Factory.CodeTransition(),
Factory.MetaCode("section Header {")
.AutoCompleteWith("}", atEndOfSpan: true)
.Accepts(AcceptedCharacters.Any),
new MarkupBlock(
Factory.Markup("\r\n<p>Foo</p>"))),
new RazorError(String.Format(RazorResources.ParseError_Expected_X, "}"),
29, 1, 10));
}
[Fact]
public void VerbatimBlockAutoCompleteAtStartOfFile()
{
ParseBlockTest("@{" + Environment.NewLine
+ "<p></p>",
new StatementBlock(
Factory.CodeTransition(),
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.Code("\r\n")
.AsStatement()
.With(new AutoCompleteEditHandler(CSharpLanguageCharacteristics.Instance.TokenizeString) { AutoCompleteString = "}" }),
new MarkupBlock(
Factory.Markup(@"<p></p>")
.With(new MarkupCodeGenerator())
.Accepts(AcceptedCharacters.None)
),
Factory.Span(SpanKind.Code, new CSharpSymbol(Factory.LocationTracker.CurrentLocation, String.Empty, CSharpSymbolType.Unknown))
.With(new StatementCodeGenerator())
),
new RazorError(String.Format(RazorResources.ParseError_Expected_EndOfBlock_Before_EOF, RazorResources.BlockName_Code, "}", "{"),
1, 0, 1));
}
}
}

View File

@ -0,0 +1,733 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.Razor.Generator;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Resources;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.AspNet.Razor.Text;
using Microsoft.AspNet.Razor.Tokenizer.Symbols;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
{
public class CSharpBlockTest : CsHtmlCodeParserTestBase
{
[Fact]
public void ParseBlockMethodThrowsArgNullExceptionOnNullContext()
{
// Arrange
CSharpCodeParser parser = new CSharpCodeParser();
// Act and Assert
Assert.Throws<InvalidOperationException>(() => parser.ParseBlock(), RazorResources.Parser_Context_Not_Set);
}
[Fact]
public void BalancingBracketsIgnoresStringLiteralCharactersAndBracketsInsideSingleLineComments()
{
SingleSpanBlockTest(@"if(foo) {
// bar } "" baz '
zoop();
}", BlockType.Statement, SpanKind.Code);
}
[Fact]
public void NestedCodeBlockWithAtCausesError()
{
ParseBlockTest("if (true) { @if(false) { } }",
new StatementBlock(
Factory.Code("if (true) { ").AsStatement(),
new StatementBlock(
Factory.CodeTransition(),
Factory.Code("if(false) { }").AsStatement()
),
Factory.Code(" }").AsStatement()),
new RazorError(
String.Format(RazorResources.ParseError_Unexpected_Keyword_After_At,
"if"),
new SourceLocation(13, 0, 13)));
}
[Fact]
public void BalancingBracketsIgnoresStringLiteralCharactersAndBracketsInsideBlockComments()
{
SingleSpanBlockTest(
@"if(foo) {
/* bar } "" */ ' baz } '
zoop();
}", BlockType.Statement, SpanKind.Code);
}
[Fact]
public void ParseBlockSkipsParenthesisedExpressionAndThenBalancesBracesIfFirstIdentifierIsForKeyword()
{
SingleSpanBlockTest("for(int i = 0; i < 10; new Foo { Bar = \"baz\" }) { Debug.WriteLine(@\"foo } bar\"); }", BlockType.Statement, SpanKind.Code, acceptedCharacters: AcceptedCharacters.None);
}
[Fact]
public void ParseBlockSkipsParenthesisedExpressionAndThenBalancesBracesIfFirstIdentifierIsForeachKeyword()
{
SingleSpanBlockTest("foreach(int i = 0; i < 10; new Foo { Bar = \"baz\" }) { Debug.WriteLine(@\"foo } bar\"); }", BlockType.Statement, SpanKind.Code, acceptedCharacters: AcceptedCharacters.None);
}
[Fact]
public void ParseBlockSkipsParenthesisedExpressionAndThenBalancesBracesIfFirstIdentifierIsWhileKeyword()
{
SingleSpanBlockTest("while(int i = 0; i < 10; new Foo { Bar = \"baz\" }) { Debug.WriteLine(@\"foo } bar\"); }", BlockType.Statement, SpanKind.Code, acceptedCharacters: AcceptedCharacters.None);
}
[Fact]
public void ParseBlockSkipsParenthesisedExpressionAndThenBalancesBracesIfFirstIdentifierIsUsingKeywordFollowedByParen()
{
SingleSpanBlockTest("using(int i = 0; i < 10; new Foo { Bar = \"baz\" }) { Debug.WriteLine(@\"foo } bar\"); }", BlockType.Statement, SpanKind.Code, acceptedCharacters: AcceptedCharacters.None);
}
[Fact]
public void ParseBlockSupportsUsingsNestedWithinOtherBlocks()
{
SingleSpanBlockTest("if(foo) { using(int i = 0; i < 10; new Foo { Bar = \"baz\" }) { Debug.WriteLine(@\"foo } bar\"); } }", BlockType.Statement, SpanKind.Code);
}
[Fact]
public void ParseBlockSkipsParenthesisedExpressionAndThenBalancesBracesIfFirstIdentifierIsIfKeywordWithNoElseBranches()
{
SingleSpanBlockTest("if(int i = 0; i < 10; new Foo { Bar = \"baz\" }) { Debug.WriteLine(@\"foo } bar\"); }", BlockType.Statement, SpanKind.Code);
}
[Fact]
public void ParseBlockAllowsEmptyBlockStatement()
{
SingleSpanBlockTest("if(false) { }", BlockType.Statement, SpanKind.Code);
}
[Fact]
public void ParseBlockTerminatesParenBalancingAtEOF()
{
ImplicitExpressionTest("Html.En(code()", "Html.En(code()",
AcceptedCharacters.Any,
new RazorError(
String.Format(RazorResources.ParseError_Expected_CloseBracket_Before_EOF,
"(", ")"),
new SourceLocation(8, 0, 8)));
}
[Fact]
public void ParseBlockSupportsBlockCommentBetweenIfAndElseClause()
{
SingleSpanBlockTest("if(foo) { bar(); } /* Foo */ /* Bar */ else { baz(); }", BlockType.Statement, SpanKind.Code, acceptedCharacters: AcceptedCharacters.None);
}
[Fact]
public void ParseBlockSupportsRazorCommentBetweenIfAndElseClause()
{
RunRazorCommentBetweenClausesTest("if(foo) { bar(); } ", " else { baz(); }", acceptedCharacters: AcceptedCharacters.None);
}
[Fact]
public void ParseBlockSupportsBlockCommentBetweenElseIfAndElseClause()
{
SingleSpanBlockTest("if(foo) { bar(); } else if(bar) { baz(); } /* Foo */ /* Bar */ else { biz(); }", BlockType.Statement, SpanKind.Code, acceptedCharacters: AcceptedCharacters.None);
}
[Fact]
public void ParseBlockSupportsRazorCommentBetweenElseIfAndElseClause()
{
RunRazorCommentBetweenClausesTest("if(foo) { bar(); } else if(bar) { baz(); } ", " else { baz(); }", acceptedCharacters: AcceptedCharacters.None);
}
[Fact]
public void ParseBlockSupportsBlockCommentBetweenIfAndElseIfClause()
{
SingleSpanBlockTest("if(foo) { bar(); } /* Foo */ /* Bar */ else if(bar) { baz(); }", BlockType.Statement, SpanKind.Code);
}
[Fact]
public void ParseBlockSupportsRazorCommentBetweenIfAndElseIfClause()
{
RunRazorCommentBetweenClausesTest("if(foo) { bar(); } ", " else if(bar) { baz(); }");
}
[Fact]
public void ParseBlockSupportsLineCommentBetweenIfAndElseClause()
{
SingleSpanBlockTest(@"if(foo) { bar(); }
// Foo
// Bar
else { baz(); }", BlockType.Statement, SpanKind.Code, acceptedCharacters: AcceptedCharacters.None);
}
[Fact]
public void ParseBlockSupportsLineCommentBetweenElseIfAndElseClause()
{
SingleSpanBlockTest(@"if(foo) { bar(); } else if(bar) { baz(); }
// Foo
// Bar
else { biz(); }", BlockType.Statement, SpanKind.Code, acceptedCharacters: AcceptedCharacters.None);
}
[Fact]
public void ParseBlockSupportsLineCommentBetweenIfAndElseIfClause()
{
SingleSpanBlockTest(@"if(foo) { bar(); }
// Foo
// Bar
else if(bar) { baz(); }", BlockType.Statement, SpanKind.Code);
}
[Fact]
public void ParseBlockParsesElseIfBranchesOfIfStatement()
{
const string ifStatement = @"if(int i = 0; i < 10; new Foo { Bar = ""baz"" }) {
Debug.WriteLine(@""foo } bar"");
}";
const string elseIfBranch = @" else if(int i = 0; i < 10; new Foo { Bar = ""baz"" }) {
Debug.WriteLine(@""bar } baz"");
}";
const string document = ifStatement + elseIfBranch;
SingleSpanBlockTest(document, BlockType.Statement, SpanKind.Code);
}
[Fact]
public void ParseBlockParsesMultipleElseIfBranchesOfIfStatement()
{
const string ifStatement = @"if(int i = 0; i < 10; new Foo { Bar = ""baz"" }) {
Debug.WriteLine(@""foo } bar"");
}";
const string elseIfBranch = @" else if(int i = 0; i < 10; new Foo { Bar = ""baz"" }) {
Debug.WriteLine(@""bar } baz"");
}";
const string document = ifStatement + elseIfBranch + elseIfBranch + elseIfBranch + elseIfBranch;
SingleSpanBlockTest(document, BlockType.Statement, SpanKind.Code);
}
[Fact]
public void ParseBlockParsesMultipleElseIfBranchesOfIfStatementFollowedByOneElseBranch()
{
const string ifStatement = @"if(int i = 0; i < 10; new Foo { Bar = ""baz"" }) {
Debug.WriteLine(@""foo } bar"");
}";
const string elseIfBranch = @" else if(int i = 0; i < 10; new Foo { Bar = ""baz"" }) {
Debug.WriteLine(@""bar } baz"");
}";
const string elseBranch = @" else { Debug.WriteLine(@""bar } baz""); }";
const string document = ifStatement + elseIfBranch + elseIfBranch + elseBranch;
SingleSpanBlockTest(document, BlockType.Statement, SpanKind.Code, acceptedCharacters: AcceptedCharacters.None);
}
[Fact]
public void ParseBlockStopsParsingCodeAfterElseBranch()
{
const string ifStatement = @"if(int i = 0; i < 10; new Foo { Bar = ""baz"" }) {
Debug.WriteLine(@""foo } bar"");
}";
const string elseIfBranch = @" else if(int i = 0; i < 10; new Foo { Bar = ""baz"" }) {
Debug.WriteLine(@""bar } baz"");
}";
const string elseBranch = @" else { Debug.WriteLine(@""bar } baz""); }";
const string document = ifStatement + elseIfBranch + elseBranch + elseIfBranch;
const string expected = ifStatement + elseIfBranch + elseBranch;
ParseBlockTest(document, new StatementBlock(Factory.Code(expected).AsStatement().Accepts(AcceptedCharacters.None)));
}
[Fact]
public void ParseBlockStopsParsingIfIfStatementNotFollowedByElse()
{
const string document = @"if(int i = 0; i < 10; new Foo { Bar = ""baz"" }) {
Debug.WriteLine(@""foo } bar"");
}";
SingleSpanBlockTest(document, BlockType.Statement, SpanKind.Code);
}
[Fact]
public void ParseBlockAcceptsElseIfWithNoCondition()
{
// We don't want to be a full C# parser - If the else if is missing it's condition, the C# compiler can handle that, we have all the info we need to keep parsing
const string ifBranch = @"if(int i = 0; i < 10; new Foo { Bar = ""baz"" }) {
Debug.WriteLine(@""foo } bar"");
}";
const string elseIfBranch = @" else if { foo(); }";
const string document = ifBranch + elseIfBranch;
SingleSpanBlockTest(document, BlockType.Statement, SpanKind.Code);
}
[Fact]
public void ParseBlockCorrectlyParsesDoWhileBlock()
{
SingleSpanBlockTest("do { var foo = bar; } while(foo != bar);", BlockType.Statement, SpanKind.Code, acceptedCharacters: AcceptedCharacters.None);
}
[Fact]
public void ParseBlockCorrectlyParsesDoWhileBlockMissingSemicolon()
{
SingleSpanBlockTest("do { var foo = bar; } while(foo != bar)", BlockType.Statement, SpanKind.Code);
}
[Fact]
public void ParseBlockCorrectlyParsesDoWhileBlockMissingWhileCondition()
{
SingleSpanBlockTest("do { var foo = bar; } while", BlockType.Statement, SpanKind.Code);
}
[Fact]
public void ParseBlockCorrectlyParsesDoWhileBlockMissingWhileConditionWithSemicolon()
{
SingleSpanBlockTest("do { var foo = bar; } while;", BlockType.Statement, SpanKind.Code, acceptedCharacters: AcceptedCharacters.None);
}
[Fact]
public void ParseBlockCorrectlyParsesDoWhileBlockMissingWhileClauseEntirely()
{
SingleSpanBlockTest("do { var foo = bar; } narf;", "do { var foo = bar; }", BlockType.Statement, SpanKind.Code);
}
[Fact]
public void ParseBlockSupportsBlockCommentBetweenDoAndWhileClause()
{
SingleSpanBlockTest("do { var foo = bar; } /* Foo */ /* Bar */ while(true);", BlockType.Statement, SpanKind.Code, acceptedCharacters: AcceptedCharacters.None);
}
[Fact]
public void ParseBlockSupportsLineCommentBetweenDoAndWhileClause()
{
SingleSpanBlockTest(@"do { var foo = bar; }
// Foo
// Bar
while(true);", BlockType.Statement, SpanKind.Code, acceptedCharacters: AcceptedCharacters.None);
}
[Fact]
public void ParseBlockSupportsRazorCommentBetweenDoAndWhileClause()
{
RunRazorCommentBetweenClausesTest("do { var foo = bar; } ", " while(true);", acceptedCharacters: AcceptedCharacters.None);
}
[Fact]
public void ParseBlockCorrectlyParsesMarkupInDoWhileBlock()
{
ParseBlockTest("@do { var foo = bar; <p>Foo</p> foo++; } while (foo<bar>);",
new StatementBlock(
Factory.CodeTransition(),
Factory.Code("do { var foo = bar;").AsStatement(),
new MarkupBlock(
Factory.Markup(" <p>Foo</p> ").Accepts(AcceptedCharacters.None)
),
Factory.Code("foo++; } while (foo<bar>);").AsStatement().Accepts(AcceptedCharacters.None)
));
}
[Fact]
public void ParseBlockSkipsParenthesisedExpressionAndThenBalancesBracesIfFirstIdentifierIsSwitchKeyword()
{
SingleSpanBlockTest(@"switch(foo) {
case 0:
break;
case 1:
{
break;
}
case 2:
return;
default:
return;
}", BlockType.Statement, SpanKind.Code, acceptedCharacters: AcceptedCharacters.None);
}
[Fact]
public void ParseBlockSkipsParenthesisedExpressionAndThenBalancesBracesIfFirstIdentifierIsLockKeyword()
{
SingleSpanBlockTest("lock(foo) { Debug.WriteLine(@\"foo } bar\"); }", BlockType.Statement, SpanKind.Code, acceptedCharacters: AcceptedCharacters.None);
}
[Fact]
public void ParseBlockHasErrorsIfNamespaceImportMissingSemicolon()
{
NamespaceImportTest("using Foo.Bar.Baz", " Foo.Bar.Baz", acceptedCharacters: AcceptedCharacters.NonWhiteSpace | AcceptedCharacters.WhiteSpace, location: new SourceLocation(17, 0, 17));
}
[Fact]
public void ParseBlockHasErrorsIfNamespaceAliasMissingSemicolon()
{
NamespaceImportTest("using Foo.Bar.Baz = FooBarBaz", " Foo.Bar.Baz = FooBarBaz", acceptedCharacters: AcceptedCharacters.NonWhiteSpace | AcceptedCharacters.WhiteSpace, location: new SourceLocation(29, 0, 29));
}
[Fact]
public void ParseBlockParsesNamespaceImportWithSemicolonForUsingKeywordIfIsInValidFormat()
{
NamespaceImportTest("using Foo.Bar.Baz;", " Foo.Bar.Baz", AcceptedCharacters.NonWhiteSpace | AcceptedCharacters.WhiteSpace);
}
[Fact]
public void ParseBlockDoesntCaptureWhitespaceAfterUsing()
{
ParseBlockTest("using Foo ",
new DirectiveBlock(
Factory.Code("using Foo")
.AsNamespaceImport(" Foo", CSharpCodeParser.UsingKeywordLength)
.Accepts(AcceptedCharacters.NonWhiteSpace | AcceptedCharacters.WhiteSpace)));
}
[Fact]
public void ParseBlockParsesNamespaceAliasWithSemicolonForUsingKeywordIfIsInValidFormat()
{
NamespaceImportTest("using FooBarBaz = FooBarBaz;", " FooBarBaz = FooBarBaz", AcceptedCharacters.NonWhiteSpace | AcceptedCharacters.WhiteSpace);
}
[Fact]
public void ParseBlockTerminatesUsingKeywordAtEOFAndOutputsFileCodeBlock()
{
SingleSpanBlockTest("using ", BlockType.Statement, SpanKind.Code);
}
[Fact]
public void ParseBlockTerminatesSingleLineCommentAtEndOfFile()
{
const string document = "foreach(var f in Foo) { // foo bar baz";
SingleSpanBlockTest(document, document, BlockType.Statement, SpanKind.Code,
new RazorError(String.Format(RazorResources.ParseError_Expected_EndOfBlock_Before_EOF, "foreach", '}', '{'), SourceLocation.Zero));
}
[Fact]
public void ParseBlockTerminatesBlockCommentAtEndOfFile()
{
const string document = "foreach(var f in Foo) { /* foo bar baz";
SingleSpanBlockTest(document, document, BlockType.Statement, SpanKind.Code,
new RazorError(String.Format(RazorResources.ParseError_BlockComment_Not_Terminated), 24, 0, 24),
new RazorError(String.Format(RazorResources.ParseError_Expected_EndOfBlock_Before_EOF, "foreach", '}', '{'), SourceLocation.Zero));
}
[Fact]
public void ParseBlockTerminatesSingleSlashAtEndOfFile()
{
const string document = "foreach(var f in Foo) { / foo bar baz";
SingleSpanBlockTest(document, document, BlockType.Statement, SpanKind.Code,
new RazorError(String.Format(RazorResources.ParseError_Expected_EndOfBlock_Before_EOF, "foreach", '}', '{'), SourceLocation.Zero));
}
[Fact]
public void ParseBlockSupportsBlockCommentBetweenTryAndFinallyClause()
{
SingleSpanBlockTest("try { bar(); } /* Foo */ /* Bar */ finally { baz(); }", BlockType.Statement, SpanKind.Code, acceptedCharacters: AcceptedCharacters.None);
}
[Fact]
public void ParseBlockSupportsRazorCommentBetweenTryAndFinallyClause()
{
RunRazorCommentBetweenClausesTest("try { bar(); } ", " finally { biz(); }", acceptedCharacters: AcceptedCharacters.None);
}
[Fact]
public void ParseBlockSupportsBlockCommentBetweenCatchAndFinallyClause()
{
SingleSpanBlockTest("try { bar(); } catch(bar) { baz(); } /* Foo */ /* Bar */ finally { biz(); }", BlockType.Statement, SpanKind.Code, acceptedCharacters: AcceptedCharacters.None);
}
[Fact]
public void ParseBlockSupportsRazorCommentBetweenCatchAndFinallyClause()
{
RunRazorCommentBetweenClausesTest("try { bar(); } catch(bar) { baz(); } ", " finally { biz(); }", acceptedCharacters: AcceptedCharacters.None);
}
[Fact]
public void ParseBlockSupportsBlockCommentBetweenTryAndCatchClause()
{
SingleSpanBlockTest("try { bar(); } /* Foo */ /* Bar */ catch(bar) { baz(); }", BlockType.Statement, SpanKind.Code);
}
[Fact]
public void ParseBlockSupportsRazorCommentBetweenTryAndCatchClause()
{
RunRazorCommentBetweenClausesTest("try { bar(); }", " catch(bar) { baz(); }");
}
[Fact]
public void ParseBlockSupportsLineCommentBetweenTryAndFinallyClause()
{
SingleSpanBlockTest(@"try { bar(); }
// Foo
// Bar
finally { baz(); }", BlockType.Statement, SpanKind.Code, acceptedCharacters: AcceptedCharacters.None);
}
[Fact]
public void ParseBlockSupportsLineCommentBetweenCatchAndFinallyClause()
{
SingleSpanBlockTest(@"try { bar(); } catch(bar) { baz(); }
// Foo
// Bar
finally { biz(); }", BlockType.Statement, SpanKind.Code, acceptedCharacters: AcceptedCharacters.None);
}
[Fact]
public void ParseBlockSupportsLineCommentBetweenTryAndCatchClause()
{
SingleSpanBlockTest(@"try { bar(); }
// Foo
// Bar
catch(bar) { baz(); }", BlockType.Statement, SpanKind.Code);
}
[Fact]
public void ParseBlockSupportsTryStatementWithNoAdditionalClauses()
{
SingleSpanBlockTest("try { var foo = new { } }", BlockType.Statement, SpanKind.Code);
}
[Fact]
public void ParseBlockSupportsMarkupWithinTryClause()
{
RunSimpleWrappedMarkupTest("try {", " <p>Foo</p> ", "}");
}
[Fact]
public void ParseBlockSupportsTryStatementWithOneCatchClause()
{
SingleSpanBlockTest("try { var foo = new { } } catch(Foo Bar Baz) { var foo = new { } }", BlockType.Statement, SpanKind.Code);
}
[Fact]
public void ParseBlockSupportsMarkupWithinCatchClause()
{
RunSimpleWrappedMarkupTest("try { var foo = new { } } catch(Foo Bar Baz) {", " <p>Foo</p> ", "}");
}
[Fact]
public void ParseBlockSupportsTryStatementWithMultipleCatchClause()
{
SingleSpanBlockTest("try { var foo = new { } } catch(Foo Bar Baz) { var foo = new { } } catch(Foo Bar Baz) { var foo = new { } } catch(Foo Bar Baz) { var foo = new { } }", BlockType.Statement, SpanKind.Code);
}
[Fact]
public void ParseBlockSupportsExceptionLessCatchClauses()
{
SingleSpanBlockTest("try { var foo = new { } } catch { var foo = new { } }", BlockType.Statement, SpanKind.Code);
}
[Fact]
public void ParseBlockSupportsMarkupWithinAdditionalCatchClauses()
{
RunSimpleWrappedMarkupTest("try { var foo = new { } } catch(Foo Bar Baz) { var foo = new { } } catch(Foo Bar Baz) { var foo = new { } } catch(Foo Bar Baz) {", " <p>Foo</p> ", "}");
}
[Fact]
public void ParseBlockSupportsTryStatementWithFinallyClause()
{
SingleSpanBlockTest("try { var foo = new { } } finally { var foo = new { } }", BlockType.Statement, SpanKind.Code, acceptedCharacters: AcceptedCharacters.None);
}
[Fact]
public void ParseBlockSupportsMarkupWithinFinallyClause()
{
RunSimpleWrappedMarkupTest("try { var foo = new { } } finally {", " <p>Foo</p> ", "}", acceptedCharacters: AcceptedCharacters.None);
}
[Fact]
public void ParseBlockStopsParsingCatchClausesAfterFinallyBlock()
{
string expectedContent = "try { var foo = new { } } finally { var foo = new { } }";
SingleSpanBlockTest(expectedContent + " catch(Foo Bar Baz) { }", expectedContent, BlockType.Statement, SpanKind.Code, acceptedCharacters: AcceptedCharacters.None);
}
[Fact]
public void ParseBlockDoesNotAllowMultipleFinallyBlocks()
{
string expectedContent = "try { var foo = new { } } finally { var foo = new { } }";
SingleSpanBlockTest(expectedContent + " finally { }", expectedContent, BlockType.Statement, SpanKind.Code, acceptedCharacters: AcceptedCharacters.None);
}
[Fact]
public void ParseBlockAcceptsTrailingDotIntoImplicitExpressionWhenEmbeddedInCode()
{
// Arrange
ParseBlockTest(@"if(foo) { @foo. }",
new StatementBlock(
Factory.Code("if(foo) { ").AsStatement(),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("foo.")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords, acceptTrailingDot: true)
.Accepts(AcceptedCharacters.NonWhiteSpace)
),
Factory.Code(" }").AsStatement()
));
}
[Fact]
public void ParseBlockParsesExpressionOnSwitchCharacterFollowedByOpenParen()
{
// Arrange
ParseBlockTest(@"if(foo) { @(foo + bar) }",
new StatementBlock(
Factory.Code("if(foo) { ").AsStatement(),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.MetaCode("(").Accepts(AcceptedCharacters.None),
Factory.Code("foo + bar").AsExpression(),
Factory.MetaCode(")").Accepts(AcceptedCharacters.None)
),
Factory.Code(" }").AsStatement()
));
}
[Fact]
public void ParseBlockParsesExpressionOnSwitchCharacterFollowedByIdentifierStart()
{
// Arrange
ParseBlockTest(@"if(foo) { @foo[4].bar() }",
new StatementBlock(
Factory.Code("if(foo) { ").AsStatement(),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("foo[4].bar()")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords, acceptTrailingDot: true)
.Accepts(AcceptedCharacters.NonWhiteSpace)
),
Factory.Code(" }").AsStatement()
));
}
[Fact]
public void ParseBlockTreatsDoubleAtSignAsEscapeSequenceIfAtStatementStart()
{
// Arrange
ParseBlockTest(@"if(foo) { @@class.Foo() }",
new StatementBlock(
Factory.Code("if(foo) { ").AsStatement(),
Factory.Code("@").Hidden(),
Factory.Code("@class.Foo() }").AsStatement()
));
}
[Fact]
public void ParseBlockTreatsAtSignsAfterFirstPairAsPartOfCSharpStatement()
{
// Arrange
ParseBlockTest(@"if(foo) { @@@@class.Foo() }",
new StatementBlock(
Factory.Code("if(foo) { ").AsStatement(),
Factory.Code("@").Hidden(),
Factory.Code("@@@class.Foo() }").AsStatement()
));
}
[Fact]
public void ParseBlockDoesNotParseMarkupStatementOrExpressionOnSwitchCharacterNotFollowedByOpenAngleOrColon()
{
// Arrange
ParseBlockTest("if(foo) { @\"Foo\".ToString(); }",
new StatementBlock(
Factory.Code("if(foo) { @\"Foo\".ToString(); }").AsStatement()));
}
[Fact]
public void ParsersCanNestRecursively()
{
// Arrange
ParseBlockTest("foreach(var c in db.Categories) {" + Environment.NewLine
+ " <div>" + Environment.NewLine
+ " <h1>@c.Name</h1>" + Environment.NewLine
+ " <ul>" + Environment.NewLine
+ " @foreach(var p in c.Products) {" + Environment.NewLine
+ " <li><a href=\"@Html.ActionUrl(\"Products\", \"Detail\", new { id = p.Id })\">@p.Name</a></li>" + Environment.NewLine
+ " }" + Environment.NewLine
+ " </ul>" + Environment.NewLine
+ " </div>" + Environment.NewLine
+ " }",
new StatementBlock(
Factory.Code("foreach(var c in db.Categories) {\r\n").AsStatement(),
new MarkupBlock(
Factory.Markup(" <div>\r\n <h1>"),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("c.Name")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
Factory.Markup("</h1>\r\n <ul>\r\n"),
new StatementBlock(
Factory.Code(@" ").AsStatement(),
Factory.CodeTransition(),
Factory.Code("foreach(var p in c.Products) {\r\n").AsStatement(),
new MarkupBlock(
Factory.Markup(" <li><a"),
new MarkupBlock(new AttributeBlockCodeGenerator("href", new LocationTagged<string>(" href=\"", 193, 5, 30), new LocationTagged<string>("\"", 256, 5, 93)),
Factory.Markup(" href=\"").With(SpanCodeGenerator.Null),
new MarkupBlock(new DynamicAttributeBlockCodeGenerator(new LocationTagged<string>(String.Empty, 200, 5, 37), 200, 5, 37),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("Html.ActionUrl(\"Products\", \"Detail\", new { id = p.Id })")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace))),
Factory.Markup("\"").With(SpanCodeGenerator.Null)),
Factory.Markup(">"),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("p.Name")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
Factory.Markup("</a></li>\r\n").Accepts(AcceptedCharacters.None)),
Factory.Code(" }\r\n").AsStatement().Accepts(AcceptedCharacters.None)),
Factory.Markup(" </ul>\r\n </div>\r\n")
.Accepts(AcceptedCharacters.None)),
Factory.Code(" }").AsStatement().Accepts(AcceptedCharacters.None)));
}
private void RunRazorCommentBetweenClausesTest(string preComment, string postComment, AcceptedCharacters acceptedCharacters = AcceptedCharacters.Any)
{
ParseBlockTest(preComment + "@* Foo *@ @* Bar *@" + postComment,
new StatementBlock(
Factory.Code(preComment).AsStatement(),
new CommentBlock(
Factory.CodeTransition(CSharpSymbolType.RazorCommentTransition),
Factory.MetaCode("*", CSharpSymbolType.RazorCommentStar).Accepts(AcceptedCharacters.None),
Factory.Comment(" Foo ", CSharpSymbolType.RazorComment),
Factory.MetaCode("*", CSharpSymbolType.RazorCommentStar).Accepts(AcceptedCharacters.None),
Factory.CodeTransition(CSharpSymbolType.RazorCommentTransition)
),
Factory.Code(" ").AsStatement(),
new CommentBlock(
Factory.CodeTransition(CSharpSymbolType.RazorCommentTransition),
Factory.MetaCode("*", CSharpSymbolType.RazorCommentStar).Accepts(AcceptedCharacters.None),
Factory.Comment(" Bar ", CSharpSymbolType.RazorComment),
Factory.MetaCode("*", CSharpSymbolType.RazorCommentStar).Accepts(AcceptedCharacters.None),
Factory.CodeTransition(CSharpSymbolType.RazorCommentTransition)
),
Factory.Code(postComment).AsStatement().Accepts(acceptedCharacters)));
}
private void RunSimpleWrappedMarkupTest(string prefix, string markup, string suffix, AcceptedCharacters acceptedCharacters = AcceptedCharacters.Any)
{
ParseBlockTest(prefix + markup + suffix,
new StatementBlock(
Factory.Code(prefix).AsStatement(),
new MarkupBlock(
Factory.Markup(markup).Accepts(AcceptedCharacters.None)
),
Factory.Code(suffix).AsStatement().Accepts(acceptedCharacters)
));
}
private void NamespaceImportTest(string content, string expectedNS, AcceptedCharacters acceptedCharacters = AcceptedCharacters.None, string errorMessage = null, SourceLocation? location = null)
{
var errors = new RazorError[0];
if (!String.IsNullOrEmpty(errorMessage) && location.HasValue)
{
errors = new RazorError[]
{
new RazorError(errorMessage, location.Value)
};
}
ParseBlockTest(content,
new DirectiveBlock(
Factory.Code(content)
.AsNamespaceImport(expectedNS, CSharpCodeParser.UsingKeywordLength)
.Accepts(acceptedCharacters)),
errors);
}
}
}

View File

@ -0,0 +1,163 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using Microsoft.AspNet.Razor.Generator;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.AspNet.Razor.Text;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
{
public class CSharpDirectivesTest : CsHtmlCodeParserTestBase
{
[Fact]
public void InheritsDirective()
{
ParseBlockTest("@inherits System.Web.WebPages.WebPage",
new DirectiveBlock(
Factory.CodeTransition(),
Factory.MetaCode(SyntaxConstants.CSharp.InheritsKeyword + " ")
.Accepts(AcceptedCharacters.None),
Factory.Code("System.Web.WebPages.WebPage")
.AsBaseType("System.Web.WebPages.WebPage")));
}
[Fact]
public void InheritsDirectiveSupportsArrays()
{
ParseBlockTest("@inherits string[[]][]",
new DirectiveBlock(
Factory.CodeTransition(),
Factory.MetaCode(SyntaxConstants.CSharp.InheritsKeyword + " ")
.Accepts(AcceptedCharacters.None),
Factory.Code("string[[]][]")
.AsBaseType("string[[]][]")));
}
[Fact]
public void InheritsDirectiveSupportsNestedGenerics()
{
ParseBlockTest("@inherits System.Web.Mvc.WebViewPage<IEnumerable<MvcApplication2.Models.RegisterModel>>",
new DirectiveBlock(
Factory.CodeTransition(),
Factory.MetaCode(SyntaxConstants.CSharp.InheritsKeyword + " ")
.Accepts(AcceptedCharacters.None),
Factory.Code("System.Web.Mvc.WebViewPage<IEnumerable<MvcApplication2.Models.RegisterModel>>")
.AsBaseType("System.Web.Mvc.WebViewPage<IEnumerable<MvcApplication2.Models.RegisterModel>>")));
}
[Fact]
public void InheritsDirectiveSupportsTypeKeywords()
{
ParseBlockTest("@inherits string",
new DirectiveBlock(
Factory.CodeTransition(),
Factory.MetaCode(SyntaxConstants.CSharp.InheritsKeyword + " ")
.Accepts(AcceptedCharacters.None),
Factory.Code("string")
.AsBaseType("string")));
}
[Fact]
public void InheritsDirectiveSupportsVSTemplateTokens()
{
ParseBlockTest("@inherits $rootnamespace$.MyBase",
new DirectiveBlock(
Factory.CodeTransition(),
Factory.MetaCode(SyntaxConstants.CSharp.InheritsKeyword + " ")
.Accepts(AcceptedCharacters.None),
Factory.Code("$rootnamespace$.MyBase")
.AsBaseType("$rootnamespace$.MyBase")));
}
[Fact]
public void SessionStateDirectiveWorks()
{
ParseBlockTest("@sessionstate InProc",
new DirectiveBlock(
Factory.CodeTransition(),
Factory.MetaCode(SyntaxConstants.CSharp.SessionStateKeyword + " ")
.Accepts(AcceptedCharacters.None),
Factory.Code("InProc")
.AsRazorDirectiveAttribute("sessionstate", "InProc")
));
}
[Fact]
public void SessionStateDirectiveParsesInvalidSessionValue()
{
ParseBlockTest("@sessionstate Blah",
new DirectiveBlock(
Factory.CodeTransition(),
Factory.MetaCode(SyntaxConstants.CSharp.SessionStateKeyword + " ")
.Accepts(AcceptedCharacters.None),
Factory.Code("Blah")
.AsRazorDirectiveAttribute("sessionstate", "Blah")
));
}
[Fact]
public void FunctionsDirective()
{
ParseBlockTest("@functions { foo(); bar(); }",
new FunctionsBlock(
Factory.CodeTransition(),
Factory.MetaCode(SyntaxConstants.CSharp.FunctionsKeyword + " {")
.Accepts(AcceptedCharacters.None),
Factory.Code(" foo(); bar(); ")
.AsFunctionsBody(),
Factory.MetaCode("}")
.Accepts(AcceptedCharacters.None)));
}
[Fact]
public void EmptyFunctionsDirective()
{
ParseBlockTest("@functions { }",
new FunctionsBlock(
Factory.CodeTransition(),
Factory.MetaCode(SyntaxConstants.CSharp.FunctionsKeyword + " {")
.Accepts(AcceptedCharacters.None),
Factory.Code(" ")
.AsFunctionsBody(),
Factory.MetaCode("}")
.Accepts(AcceptedCharacters.None)));
}
[Fact]
public void SectionDirective()
{
ParseBlockTest("@section Header { <p>F{o}o</p> }",
new SectionBlock(new SectionCodeGenerator("Header"),
Factory.CodeTransition(),
Factory.MetaCode("section Header {")
.AutoCompleteWith(null, atEndOfSpan: true)
.Accepts(AcceptedCharacters.Any),
new MarkupBlock(
Factory.Markup(" <p>F", "{", "o", "}", "o", "</p> ")),
Factory.MetaCode("}")
.Accepts(AcceptedCharacters.None)));
}
[Fact]
public void HelperDirective()
{
ParseBlockTest("@helper Strong(string value) { foo(); }",
new HelperBlock(new HelperCodeGenerator(new LocationTagged<string>("Strong(string value) {", new SourceLocation(8, 0, 8)), headerComplete: true),
Factory.CodeTransition(),
Factory.MetaCode("helper ")
.Accepts(AcceptedCharacters.None),
Factory.Code("Strong(string value) {")
.Hidden()
.Accepts(AcceptedCharacters.None),
new StatementBlock(
Factory.Code(" foo(); ")
.AsStatement()
.With(new StatementCodeGenerator())),
Factory.Code("}")
.Hidden()
.Accepts(AcceptedCharacters.None)));
}
}
}

View File

@ -0,0 +1,624 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Resources;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.AspNet.Razor.Text;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
{
public class CSharpErrorTest : CsHtmlCodeParserTestBase
{
[Fact]
public void ParseBlockHandlesQuotesAfterTransition()
{
ParseBlockTest("@\"",
new ExpressionBlock(
Factory.CodeTransition(),
Factory.EmptyCSharp()
.AsImplicitExpression(KeywordSet)
.Accepts(AcceptedCharacters.NonWhiteSpace)
),
new RazorError(
String.Format(RazorResources.ParseError_Unexpected_Character_At_Start_Of_CodeBlock_CS, '"'),
1, 0, 1));
}
[Fact]
public void ParseBlockCapturesWhitespaceToEndOfLineInInvalidUsingStatementAndTreatsAsFileCode()
{
ParseBlockTest("using " + Environment.NewLine
+ Environment.NewLine,
new StatementBlock(
Factory.Code("using \r\n").AsStatement()
));
}
[Fact]
public void ParseBlockMethodOutputsOpenCurlyAsCodeSpanIfEofFoundAfterOpenCurlyBrace()
{
ParseBlockTest("{",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.EmptyCSharp()
.AsStatement()
.With(new AutoCompleteEditHandler(CSharpLanguageCharacteristics.Instance.TokenizeString) { AutoCompleteString = "}" })
),
new RazorError(
String.Format(RazorResources.ParseError_Expected_EndOfBlock_Before_EOF,
RazorResources.BlockName_Code,
"}", "{"),
SourceLocation.Zero));
}
[Fact]
public void ParseBlockMethodOutputsZeroLengthCodeSpanIfStatementBlockEmpty()
{
ParseBlockTest("{}",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.EmptyCSharp().AsStatement(),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)
));
}
[Fact]
public void ParseBlockMethodProducesErrorIfNewlineFollowsTransition()
{
ParseBlockTest("@" + Environment.NewLine,
new ExpressionBlock(
Factory.CodeTransition(),
Factory.EmptyCSharp()
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
new RazorError(RazorResources.ParseError_Unexpected_WhiteSpace_At_Start_Of_CodeBlock_CS, new SourceLocation(1, 0, 1)));
}
[Fact]
public void ParseBlockMethodProducesErrorIfWhitespaceBetweenTransitionAndBlockStartInEmbeddedExpression()
{
ParseBlockTest("{" + Environment.NewLine
+ " @ {}" + Environment.NewLine
+ "}",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.Code("\r\n ").AsStatement(),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.EmptyCSharp()
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords, acceptTrailingDot: true)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
Factory.Code(" {}\r\n").AsStatement(),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)
),
new RazorError(RazorResources.ParseError_Unexpected_WhiteSpace_At_Start_Of_CodeBlock_CS, 8, 1, 5));
}
[Fact]
public void ParseBlockMethodProducesErrorIfEOFAfterTransitionInEmbeddedExpression()
{
ParseBlockTest("{" + Environment.NewLine
+ " @",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.Code("\r\n ").AsStatement(),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.EmptyCSharp()
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords, acceptTrailingDot: true)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
Factory.EmptyCSharp().AsStatement()
),
new RazorError(RazorResources.ParseError_Unexpected_EndOfFile_At_Start_Of_CodeBlock, 8, 1, 5),
new RazorError(
String.Format(RazorResources.ParseError_Expected_EndOfBlock_Before_EOF, RazorResources.BlockName_Code, "}", "{"),
SourceLocation.Zero));
}
[Fact]
public void ParseBlockMethodParsesNothingIfFirstCharacterIsNotIdentifierStartOrParenOrBrace()
{
ParseBlockTest("@!!!",
new ExpressionBlock(
Factory.CodeTransition(),
Factory.EmptyCSharp()
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
new RazorError(
String.Format(RazorResources.ParseError_Unexpected_Character_At_Start_Of_CodeBlock_CS, "!"),
1, 0, 1));
}
[Fact]
public void ParseBlockShouldReportErrorAndTerminateAtEOFIfIfParenInExplicitExpressionUnclosed()
{
ParseBlockTest("(foo bar" + Environment.NewLine
+ "baz",
new ExpressionBlock(
Factory.MetaCode("(").Accepts(AcceptedCharacters.None),
Factory.Code("foo bar\r\nbaz").AsExpression()
),
new RazorError(
String.Format(RazorResources.ParseError_Expected_EndOfBlock_Before_EOF,
RazorResources.BlockName_ExplicitExpression, ')', '('),
new SourceLocation(0, 0, 0)));
}
[Fact]
public void ParseBlockShouldReportErrorAndTerminateAtMarkupIfIfParenInExplicitExpressionUnclosed()
{
ParseBlockTest("(foo bar" + Environment.NewLine
+ "<html>" + Environment.NewLine
+ "baz" + Environment.NewLine
+ "</html",
new ExpressionBlock(
Factory.MetaCode("(").Accepts(AcceptedCharacters.None),
Factory.Code("foo bar\r\n").AsExpression()
),
new RazorError(
String.Format(RazorResources.ParseError_Expected_EndOfBlock_Before_EOF,
RazorResources.BlockName_ExplicitExpression, ')', '('),
new SourceLocation(0, 0, 0)));
}
[Fact]
public void ParseBlockCorrectlyHandlesInCorrectTransitionsIfImplicitExpressionParensUnclosed()
{
ParseBlockTest("Href(" + Environment.NewLine
+ "<h1>@Html.Foo(Bar);</h1>" + Environment.NewLine,
new ExpressionBlock(
Factory.Code("Href(\r\n")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
),
new RazorError(
String.Format(RazorResources.ParseError_Expected_CloseBracket_Before_EOF,
"(", ")"),
new SourceLocation(4, 0, 4)));
}
[Fact]
// Test for fix to Dev10 884975 - Incorrect Error Messaging
public void ParseBlockShouldReportErrorAndTerminateAtEOFIfParenInImplicitExpressionUnclosed()
{
ParseBlockTest("Foo(Bar(Baz)" + Environment.NewLine
+ "Biz" + Environment.NewLine
+ "Boz",
new ExpressionBlock(
Factory.Code("Foo(Bar(Baz)\r\nBiz\r\nBoz")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
),
new RazorError(String.Format(RazorResources.ParseError_Expected_CloseBracket_Before_EOF,
"(", ")"),
new SourceLocation(3, 0, 3)));
}
[Fact]
// Test for fix to Dev10 884975 - Incorrect Error Messaging
public void ParseBlockShouldReportErrorAndTerminateAtMarkupIfParenInImplicitExpressionUnclosed()
{
ParseBlockTest("Foo(Bar(Baz)" + Environment.NewLine
+ "Biz" + Environment.NewLine
+ "<html>" + Environment.NewLine
+ "Boz" + Environment.NewLine
+ "</html>",
new ExpressionBlock(
Factory.Code("Foo(Bar(Baz)\r\nBiz\r\n")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
),
new RazorError(String.Format(RazorResources.ParseError_Expected_CloseBracket_Before_EOF,
"(", ")"),
new SourceLocation(3, 0, 3)));
}
[Fact]
// Test for fix to Dev10 884975 - Incorrect Error Messaging
public void ParseBlockShouldReportErrorAndTerminateAtEOFIfBracketInImplicitExpressionUnclosed()
{
ParseBlockTest("Foo[Bar[Baz]" + Environment.NewLine
+ "Biz" + Environment.NewLine
+ "Boz",
new ExpressionBlock(
Factory.Code("Foo[Bar[Baz]\r\nBiz\r\nBoz")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
),
new RazorError(
String.Format(RazorResources.ParseError_Expected_CloseBracket_Before_EOF,
"[", "]"),
new SourceLocation(3, 0, 3)));
}
[Fact]
// Test for fix to Dev10 884975 - Incorrect Error Messaging
public void ParseBlockShouldReportErrorAndTerminateAtMarkupIfBracketInImplicitExpressionUnclosed()
{
ParseBlockTest("Foo[Bar[Baz]" + Environment.NewLine
+ "Biz" + Environment.NewLine
+ "<b>" + Environment.NewLine
+ "Boz" + Environment.NewLine
+ "</b>",
new ExpressionBlock(
Factory.Code("Foo[Bar[Baz]\r\nBiz\r\n")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
),
new RazorError(
String.Format(RazorResources.ParseError_Expected_CloseBracket_Before_EOF,
"[", "]"),
new SourceLocation(3, 0, 3)));
}
// Simple EOF handling errors:
[Fact]
public void ParseBlockReportsErrorIfExplicitCodeBlockUnterminatedAtEOF()
{
ParseBlockTest("{ var foo = bar; if(foo != null) { bar(); } ",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.Code(" var foo = bar; if(foo != null) { bar(); } ").AsStatement()
),
new RazorError(
String.Format(RazorResources.ParseError_Expected_EndOfBlock_Before_EOF,
RazorResources.BlockName_Code, '}', '{'),
SourceLocation.Zero));
}
[Fact]
public void ParseBlockReportsErrorIfClassBlockUnterminatedAtEOF()
{
ParseBlockTest("functions { var foo = bar; if(foo != null) { bar(); } ",
new FunctionsBlock(
Factory.MetaCode("functions {").Accepts(AcceptedCharacters.None),
Factory.Code(" var foo = bar; if(foo != null) { bar(); } ").AsFunctionsBody()
),
new RazorError(
String.Format(RazorResources.ParseError_Expected_EndOfBlock_Before_EOF,
"functions", '}', '{'),
SourceLocation.Zero));
}
[Fact]
public void ParseBlockReportsErrorIfIfBlockUnterminatedAtEOF()
{
RunUnterminatedSimpleKeywordBlock("if");
}
[Fact]
public void ParseBlockReportsErrorIfElseBlockUnterminatedAtEOF()
{
ParseBlockTest("if(foo) { baz(); } else { var foo = bar; if(foo != null) { bar(); } ",
new StatementBlock(
Factory.Code("if(foo) { baz(); } else { var foo = bar; if(foo != null) { bar(); } ").AsStatement()
),
new RazorError(
String.Format(RazorResources.ParseError_Expected_EndOfBlock_Before_EOF,
"else", '}', '{'),
new SourceLocation(19, 0, 19)));
}
[Fact]
public void ParseBlockReportsErrorIfElseIfBlockUnterminatedAtEOF()
{
ParseBlockTest("if(foo) { baz(); } else if { var foo = bar; if(foo != null) { bar(); } ",
new StatementBlock(
Factory.Code("if(foo) { baz(); } else if { var foo = bar; if(foo != null) { bar(); } ").AsStatement()
),
new RazorError(
String.Format(RazorResources.ParseError_Expected_EndOfBlock_Before_EOF,
"else if", '}', '{'),
new SourceLocation(19, 0, 19)));
}
[Fact]
public void ParseBlockReportsErrorIfDoBlockUnterminatedAtEOF()
{
ParseBlockTest("do { var foo = bar; if(foo != null) { bar(); } ",
new StatementBlock(
Factory.Code("do { var foo = bar; if(foo != null) { bar(); } ").AsStatement()
),
new RazorError(
String.Format(RazorResources.ParseError_Expected_EndOfBlock_Before_EOF,
"do", '}', '{'),
SourceLocation.Zero));
}
[Fact]
public void ParseBlockReportsErrorIfTryBlockUnterminatedAtEOF()
{
ParseBlockTest("try { var foo = bar; if(foo != null) { bar(); } ",
new StatementBlock(
Factory.Code("try { var foo = bar; if(foo != null) { bar(); } ").AsStatement()
),
new RazorError(
String.Format(RazorResources.ParseError_Expected_EndOfBlock_Before_EOF,
"try", '}', '{'),
SourceLocation.Zero));
}
[Fact]
public void ParseBlockReportsErrorIfCatchBlockUnterminatedAtEOF()
{
ParseBlockTest("try { baz(); } catch(Foo) { var foo = bar; if(foo != null) { bar(); } ",
new StatementBlock(
Factory.Code("try { baz(); } catch(Foo) { var foo = bar; if(foo != null) { bar(); } ").AsStatement()
),
new RazorError(
String.Format(RazorResources.ParseError_Expected_EndOfBlock_Before_EOF,
"catch", '}', '{'),
new SourceLocation(15, 0, 15)));
}
[Fact]
public void ParseBlockReportsErrorIfFinallyBlockUnterminatedAtEOF()
{
ParseBlockTest("try { baz(); } finally { var foo = bar; if(foo != null) { bar(); } ",
new StatementBlock(
Factory.Code("try { baz(); } finally { var foo = bar; if(foo != null) { bar(); } ").AsStatement()
),
new RazorError(
String.Format(RazorResources.ParseError_Expected_EndOfBlock_Before_EOF,
"finally", '}', '{'),
new SourceLocation(15, 0, 15)));
}
[Fact]
public void ParseBlockReportsErrorIfForBlockUnterminatedAtEOF()
{
RunUnterminatedSimpleKeywordBlock("for");
}
[Fact]
public void ParseBlockReportsErrorIfForeachBlockUnterminatedAtEOF()
{
RunUnterminatedSimpleKeywordBlock("foreach");
}
[Fact]
public void ParseBlockReportsErrorIfWhileBlockUnterminatedAtEOF()
{
RunUnterminatedSimpleKeywordBlock("while");
}
[Fact]
public void ParseBlockReportsErrorIfSwitchBlockUnterminatedAtEOF()
{
RunUnterminatedSimpleKeywordBlock("switch");
}
[Fact]
public void ParseBlockReportsErrorIfLockBlockUnterminatedAtEOF()
{
RunUnterminatedSimpleKeywordBlock("lock");
}
[Fact]
public void ParseBlockReportsErrorIfUsingBlockUnterminatedAtEOF()
{
RunUnterminatedSimpleKeywordBlock("using");
}
[Fact]
public void ParseBlockRequiresControlFlowStatementsToHaveBraces()
{
string expectedMessage = String.Format(RazorResources.ParseError_SingleLine_ControlFlowStatements_Not_Allowed, "{", "<");
ParseBlockTest("if(foo) <p>Bar</p> else if(bar) <p>Baz</p> else <p>Boz</p>",
new StatementBlock(
Factory.Code("if(foo) ").AsStatement(),
new MarkupBlock(
Factory.Markup("<p>Bar</p> ").Accepts(AcceptedCharacters.None)
),
Factory.Code("else if(bar) ").AsStatement(),
new MarkupBlock(
Factory.Markup("<p>Baz</p> ").Accepts(AcceptedCharacters.None)
),
Factory.Code("else ").AsStatement(),
new MarkupBlock(
Factory.Markup("<p>Boz</p>").Accepts(AcceptedCharacters.None)
),
Factory.EmptyCSharp().AsStatement()
),
new RazorError(expectedMessage, 8, 0, 8),
new RazorError(expectedMessage, 32, 0, 32),
new RazorError(expectedMessage, 48, 0, 48));
}
[Fact]
public void ParseBlockIncludesUnexpectedCharacterInSingleStatementControlFlowStatementError()
{
ParseBlockTest("if(foo)) { var bar = foo; }",
new StatementBlock(
Factory.Code("if(foo)) { var bar = foo; }").AsStatement()
),
new RazorError(
String.Format(RazorResources.ParseError_SingleLine_ControlFlowStatements_Not_Allowed,
"{", ")"),
new SourceLocation(7, 0, 7)));
}
[Fact]
public void ParseBlockOutputsErrorIfAtSignFollowedByLessThanSignAtStatementStart()
{
ParseBlockTest("if(foo) { @<p>Bar</p> }",
new StatementBlock(
Factory.Code("if(foo) {").AsStatement(),
new MarkupBlock(
Factory.Markup(" "),
Factory.MarkupTransition(),
Factory.Markup("<p>Bar</p> ").Accepts(AcceptedCharacters.None)
),
Factory.Code("}").AsStatement()
),
new RazorError(
RazorResources.ParseError_AtInCode_Must_Be_Followed_By_Colon_Paren_Or_Identifier_Start,
10, 0, 10));
}
[Fact]
public void ParseBlockTerminatesIfBlockAtEOLWhenRecoveringFromMissingCloseParen()
{
ParseBlockTest("if(foo bar" + Environment.NewLine
+ "baz",
new StatementBlock(
Factory.Code("if(foo bar\r\n").AsStatement()
),
new RazorError(
String.Format(RazorResources.ParseError_Expected_CloseBracket_Before_EOF,
"(", ")"),
new SourceLocation(2, 0, 2)));
}
[Fact]
public void ParseBlockTerminatesForeachBlockAtEOLWhenRecoveringFromMissingCloseParen()
{
ParseBlockTest("foreach(foo bar" + Environment.NewLine
+ "baz",
new StatementBlock(
Factory.Code("foreach(foo bar\r\n").AsStatement()
),
new RazorError(
String.Format(RazorResources.ParseError_Expected_CloseBracket_Before_EOF,
"(", ")"),
new SourceLocation(7, 0, 7)));
}
[Fact]
public void ParseBlockTerminatesWhileClauseInDoStatementAtEOLWhenRecoveringFromMissingCloseParen()
{
ParseBlockTest("do { } while(foo bar" + Environment.NewLine
+ "baz",
new StatementBlock(
Factory.Code("do { } while(foo bar\r\n").AsStatement()
),
new RazorError(
String.Format(RazorResources.ParseError_Expected_CloseBracket_Before_EOF,
"(", ")"),
new SourceLocation(12, 0, 12)));
}
[Fact]
public void ParseBlockTerminatesUsingBlockAtEOLWhenRecoveringFromMissingCloseParen()
{
ParseBlockTest("using(foo bar" + Environment.NewLine
+ "baz",
new StatementBlock(
Factory.Code("using(foo bar\r\n").AsStatement()
),
new RazorError(
String.Format(RazorResources.ParseError_Expected_CloseBracket_Before_EOF,
"(", ")"),
new SourceLocation(5, 0, 5)));
}
[Fact]
public void ParseBlockResumesIfStatementAfterOpenParen()
{
ParseBlockTest("if(" + Environment.NewLine
+ "else { <p>Foo</p> }",
new StatementBlock(
Factory.Code("if(\r\nelse {").AsStatement(),
new MarkupBlock(
Factory.Markup(" <p>Foo</p> ").Accepts(AcceptedCharacters.None)
),
Factory.Code("}").AsStatement().Accepts(AcceptedCharacters.None)
),
new RazorError(
String.Format(RazorResources.ParseError_Expected_CloseBracket_Before_EOF,
"(", ")"),
new SourceLocation(2, 0, 2)));
}
[Fact]
public void ParseBlockTerminatesNormalCSharpStringsAtEOLIfEndQuoteMissing()
{
SingleSpanBlockTest("if(foo) {" + Environment.NewLine
+ " var p = \"foo bar baz" + Environment.NewLine
+ ";" + Environment.NewLine
+ "}",
BlockType.Statement, SpanKind.Code,
new RazorError(RazorResources.ParseError_Unterminated_String_Literal, 23, 1, 12));
}
[Fact]
public void ParseBlockTerminatesNormalStringAtEndOfFile()
{
SingleSpanBlockTest("if(foo) { var foo = \"blah blah blah blah blah", BlockType.Statement, SpanKind.Code,
new RazorError(RazorResources.ParseError_Unterminated_String_Literal, 20, 0, 20),
new RazorError(String.Format(RazorResources.ParseError_Expected_EndOfBlock_Before_EOF, "if", '}', '{'), SourceLocation.Zero));
}
[Fact]
public void ParseBlockTerminatesVerbatimStringAtEndOfFile()
{
SingleSpanBlockTest("if(foo) { var foo = @\"blah " + Environment.NewLine
+ "blah; " + Environment.NewLine
+ "<p>Foo</p>" + Environment.NewLine
+ "blah " + Environment.NewLine
+ "blah",
BlockType.Statement, SpanKind.Code,
new RazorError(RazorResources.ParseError_Unterminated_String_Literal, 20, 0, 20),
new RazorError(String.Format(RazorResources.ParseError_Expected_EndOfBlock_Before_EOF, "if", '}', '{'), SourceLocation.Zero));
}
[Fact]
public void ParseBlockCorrectlyParsesMarkupIncorrectyAssumedToBeWithinAStatement()
{
ParseBlockTest("if(foo) {" + Environment.NewLine
+ " var foo = \"foo bar baz" + Environment.NewLine
+ " <p>Foo is @foo</p>" + Environment.NewLine
+ "}",
new StatementBlock(
Factory.Code("if(foo) {\r\n var foo = \"foo bar baz\r\n ").AsStatement(),
new MarkupBlock(
Factory.Markup("<p>Foo is "),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("foo")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
Factory.Markup("</p>\r\n").Accepts(AcceptedCharacters.None)),
Factory.Code("}").AsStatement()
),
new RazorError(
RazorResources.ParseError_Unterminated_String_Literal,
25, 1, 14));
}
[Fact]
public void ParseBlockCorrectlyParsesAtSignInDelimitedBlock()
{
ParseBlockTest("(Request[\"description\"] ?? @photo.Description)",
new ExpressionBlock(
Factory.MetaCode("(").Accepts(AcceptedCharacters.None),
Factory.Code("Request[\"description\"] ?? @photo.Description").AsExpression(),
Factory.MetaCode(")").Accepts(AcceptedCharacters.None)
));
}
[Fact]
public void ParseBlockCorrectlyRecoversFromMissingCloseParenInExpressionWithinCode()
{
ParseBlockTest(@"{String.Format(<html></html>}",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.Code("String.Format(")
.AsStatement(),
new MarkupBlock(
Factory.Markup("<html></html>").Accepts(AcceptedCharacters.None)),
Factory.EmptyCSharp().AsStatement(),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)),
expectedErrors: new[] {
new RazorError(
String.Format(RazorResources.ParseError_Expected_CloseBracket_Before_EOF, "(", ")"),
14, 0, 14)
});
}
private void RunUnterminatedSimpleKeywordBlock(string keyword)
{
SingleSpanBlockTest(keyword + " (foo) { var foo = bar; if(foo != null) { bar(); } ", BlockType.Statement, SpanKind.Code,
new RazorError(String.Format(RazorResources.ParseError_Expected_EndOfBlock_Before_EOF, keyword, '}', '{'), SourceLocation.Zero));
}
}
}

View File

@ -0,0 +1,142 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Resources;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.AspNet.Razor.Text;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
{
public class CSharpExplicitExpressionTest : CsHtmlCodeParserTestBase
{
[Fact]
public void ParseBlockShouldOutputZeroLengthCodeSpanIfExplicitExpressionIsEmpty()
{
ParseBlockTest("@()",
new ExpressionBlock(
Factory.CodeTransition(),
Factory.MetaCode("(").Accepts(AcceptedCharacters.None),
Factory.EmptyCSharp().AsExpression(),
Factory.MetaCode(")").Accepts(AcceptedCharacters.None)
));
}
[Fact]
public void ParseBlockShouldOutputZeroLengthCodeSpanIfEOFOccursAfterStartOfExplicitExpression()
{
ParseBlockTest("@(",
new ExpressionBlock(
Factory.CodeTransition(),
Factory.MetaCode("(").Accepts(AcceptedCharacters.None),
Factory.EmptyCSharp().AsExpression()
),
new RazorError(
String.Format(RazorResources.ParseError_Expected_EndOfBlock_Before_EOF,
RazorResources.BlockName_ExplicitExpression,
")", "("),
new SourceLocation(1, 0, 1)));
}
[Fact]
public void ParseBlockShouldAcceptEscapedQuoteInNonVerbatimStrings()
{
ParseBlockTest("@(\"\\\"\")",
new ExpressionBlock(
Factory.CodeTransition(),
Factory.MetaCode("(").Accepts(AcceptedCharacters.None),
Factory.Code("\"\\\"\"").AsExpression(),
Factory.MetaCode(")").Accepts(AcceptedCharacters.None)
));
}
[Fact]
public void ParseBlockShouldAcceptEscapedQuoteInVerbatimStrings()
{
ParseBlockTest("@(@\"\"\"\")",
new ExpressionBlock(
Factory.CodeTransition(),
Factory.MetaCode("(").Accepts(AcceptedCharacters.None),
Factory.Code("@\"\"\"\"").AsExpression(),
Factory.MetaCode(")").Accepts(AcceptedCharacters.None)
));
}
[Fact]
public void ParseBlockShouldAcceptMultipleRepeatedEscapedQuoteInVerbatimStrings()
{
ParseBlockTest("@(@\"\"\"\"\"\")",
new ExpressionBlock(
Factory.CodeTransition(),
Factory.MetaCode("(").Accepts(AcceptedCharacters.None),
Factory.Code("@\"\"\"\"\"\"").AsExpression(),
Factory.MetaCode(")").Accepts(AcceptedCharacters.None)
));
}
[Fact]
public void ParseBlockShouldAcceptMultiLineVerbatimStrings()
{
ParseBlockTest(@"@(@""" + Environment.NewLine
+ @"Foo" + Environment.NewLine
+ @"Bar" + Environment.NewLine
+ @"Baz" + Environment.NewLine
+ @""")",
new ExpressionBlock(
Factory.CodeTransition(),
Factory.MetaCode("(").Accepts(AcceptedCharacters.None),
Factory.Code("@\"\r\nFoo\r\nBar\r\nBaz\r\n\"").AsExpression(),
Factory.MetaCode(")").Accepts(AcceptedCharacters.None)
));
}
[Fact]
public void ParseBlockShouldAcceptMultipleEscapedQuotesInNonVerbatimStrings()
{
ParseBlockTest("@(\"\\\"hello, world\\\"\")",
new ExpressionBlock(
Factory.CodeTransition(),
Factory.MetaCode("(").Accepts(AcceptedCharacters.None),
Factory.Code("\"\\\"hello, world\\\"\"").AsExpression(),
Factory.MetaCode(")").Accepts(AcceptedCharacters.None)
));
}
[Fact]
public void ParseBlockShouldAcceptMultipleEscapedQuotesInVerbatimStrings()
{
ParseBlockTest("@(@\"\"\"hello, world\"\"\")",
new ExpressionBlock(
Factory.CodeTransition(),
Factory.MetaCode("(").Accepts(AcceptedCharacters.None),
Factory.Code("@\"\"\"hello, world\"\"\"").AsExpression(),
Factory.MetaCode(")").Accepts(AcceptedCharacters.None)
));
}
[Fact]
public void ParseBlockShouldAcceptConsecutiveEscapedQuotesInNonVerbatimStrings()
{
ParseBlockTest("@(\"\\\"\\\"\")",
new ExpressionBlock(
Factory.CodeTransition(),
Factory.MetaCode("(").Accepts(AcceptedCharacters.None),
Factory.Code("\"\\\"\\\"\"").AsExpression(),
Factory.MetaCode(")").Accepts(AcceptedCharacters.None)
));
}
[Fact]
public void ParseBlockShouldAcceptConsecutiveEscapedQuotesInVerbatimStrings()
{
ParseBlockTest("@(@\"\"\"\"\"\")",
new ExpressionBlock(
Factory.CodeTransition(),
Factory.MetaCode("(").Accepts(AcceptedCharacters.None),
Factory.Code("@\"\"\"\"\"\"").AsExpression(),
Factory.MetaCode(")").Accepts(AcceptedCharacters.None)
));
}
}
}

View File

@ -0,0 +1,347 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.Razor.Generator;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Resources;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.AspNet.Razor.Text;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
{
public class CSharpHelperTest : CsHtmlMarkupParserTestBase
{
[Fact]
public void ParseHelperCorrectlyParsesHelperWithNoSpaceInBody()
{
ParseDocumentTest("@helper Foo(){@Bar()}",
new MarkupBlock(
Factory.EmptyHtml(),
new HelperBlock(new HelperCodeGenerator(new LocationTagged<string>("Foo(){", 8, 0, 8), headerComplete: true),
Factory.CodeTransition(),
Factory.MetaCode("helper ").Accepts(AcceptedCharacters.None),
Factory.Code("Foo(){").Hidden().Accepts(AcceptedCharacters.None),
new StatementBlock(
Factory.EmptyCSharp().AsStatement(),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("Bar()")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords, acceptTrailingDot: true)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
Factory.EmptyCSharp().AsStatement()),
Factory.Code("}").Hidden().Accepts(AcceptedCharacters.None)),
Factory.EmptyHtml()));
}
[Fact]
public void ParseHelperCorrectlyParsesIncompleteHelperPreceedingCodeBlock()
{
ParseDocumentTest("@helper" + Environment.NewLine
+ "@{}",
new MarkupBlock(
Factory.EmptyHtml(),
new HelperBlock(
Factory.CodeTransition(),
Factory.MetaCode("helper")),
Factory.Markup("\r\n"),
new StatementBlock(
Factory.CodeTransition(),
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.EmptyCSharp().AsStatement(),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)),
Factory.EmptyHtml()),
new RazorError(
String.Format(
RazorResources.ParseError_Unexpected_Character_At_Helper_Name_Start,
RazorResources.ErrorComponent_Newline),
7, 0, 7));
}
[Fact]
public void ParseHelperRequiresSpaceBeforeSignature()
{
ParseDocumentTest("@helper{",
new MarkupBlock(
Factory.EmptyHtml(),
new HelperBlock(
Factory.CodeTransition(),
Factory.MetaCode("helper")),
Factory.Markup("{")),
new RazorError(
String.Format(
RazorResources.ParseError_Unexpected_Character_At_Helper_Name_Start,
String.Format(RazorResources.ErrorComponent_Character, "{")),
7, 0, 7));
}
[Fact]
public void ParseHelperOutputsErrorButContinuesIfLParenFoundAfterHelperKeyword()
{
ParseDocumentTest("@helper () {",
new MarkupBlock(
Factory.EmptyHtml(),
new HelperBlock(new HelperCodeGenerator(new LocationTagged<string>("() {", 8, 0, 8), headerComplete: true),
Factory.CodeTransition(),
Factory.MetaCode("helper ").Accepts(AcceptedCharacters.None),
Factory.Code("() {").Hidden().Accepts(AcceptedCharacters.None),
new StatementBlock(
Factory.EmptyCSharp()
.AsStatement()
.AutoCompleteWith("}")))),
new RazorError(
String.Format(
RazorResources.ParseError_Unexpected_Character_At_Helper_Name_Start,
String.Format(RazorResources.ErrorComponent_Character, "(")),
8, 0, 8),
new RazorError(
String.Format(
RazorResources.ParseError_Expected_EndOfBlock_Before_EOF,
"helper", "}", "{"),
1, 0, 1));
}
[Fact]
public void ParseHelperStatementOutputsMarkerHelperHeaderSpanOnceKeywordComplete()
{
ParseDocumentTest("@helper ",
new MarkupBlock(
Factory.EmptyHtml(),
new HelperBlock(new HelperCodeGenerator(new LocationTagged<string>(String.Empty, 8, 0, 8), headerComplete: false),
Factory.CodeTransition(),
Factory.MetaCode("helper ").Accepts(AcceptedCharacters.None),
Factory.EmptyCSharp().Hidden())),
new RazorError(
String.Format(
RazorResources.ParseError_Unexpected_Character_At_Helper_Name_Start,
RazorResources.ErrorComponent_EndOfFile),
8, 0, 8));
}
[Fact]
public void ParseHelperStatementMarksHelperSpanAsCanGrowIfMissingTrailingSpace()
{
ParseDocumentTest("@helper",
new MarkupBlock(
Factory.EmptyHtml(),
new HelperBlock(
Factory.CodeTransition(),
Factory.MetaCode("helper").Accepts(AcceptedCharacters.Any))),
new RazorError(
String.Format(
RazorResources.ParseError_Unexpected_Character_At_Helper_Name_Start,
RazorResources.ErrorComponent_EndOfFile),
7, 0, 7));
}
[Fact]
public void ParseHelperStatementCapturesWhitespaceToEndOfLineIfHelperStatementMissingName()
{
ParseDocumentTest("@helper " + Environment.NewLine
+ " ",
new MarkupBlock(
Factory.EmptyHtml(),
new HelperBlock(new HelperCodeGenerator(new LocationTagged<string>(" ", 8, 0, 8), headerComplete: false),
Factory.CodeTransition(),
Factory.MetaCode("helper ").Accepts(AcceptedCharacters.None),
Factory.Code(" \r\n").Hidden()),
Factory.Markup(@" ")),
new RazorError(
String.Format(
RazorResources.ParseError_Unexpected_Character_At_Helper_Name_Start,
RazorResources.ErrorComponent_Newline),
30, 0, 30));
}
[Fact]
public void ParseHelperStatementCapturesWhitespaceToEndOfLineIfHelperStatementMissingOpenParen()
{
ParseDocumentTest("@helper Foo " + Environment.NewLine
+ " ",
new MarkupBlock(
Factory.EmptyHtml(),
new HelperBlock(new HelperCodeGenerator(new LocationTagged<string>("Foo ", 8, 0, 8), headerComplete: false),
Factory.CodeTransition(),
Factory.MetaCode("helper ").Accepts(AcceptedCharacters.None),
Factory.Code("Foo \r\n").Hidden()),
Factory.Markup(" ")),
new RazorError(
String.Format(RazorResources.ParseError_MissingCharAfterHelperName, "("),
15, 0, 15));
}
[Fact]
public void ParseHelperStatementCapturesAllContentToEndOfFileIfHelperStatementMissingCloseParenInParameterList()
{
ParseDocumentTest("@helper Foo(Foo Bar" + Environment.NewLine
+ "Biz" + Environment.NewLine
+ "Boz",
new MarkupBlock(
Factory.EmptyHtml(),
new HelperBlock(new HelperCodeGenerator(new LocationTagged<string>("Foo(Foo Bar\r\nBiz\r\nBoz", 8, 0, 8), headerComplete: false),
Factory.CodeTransition(),
Factory.MetaCode("helper ").Accepts(AcceptedCharacters.None),
Factory.Code("Foo(Foo Bar\r\nBiz\r\nBoz").Hidden())),
new RazorError(
RazorResources.ParseError_UnterminatedHelperParameterList,
11, 0, 11));
}
[Fact]
public void ParseHelperStatementCapturesWhitespaceToEndOfLineIfHelperStatementMissingOpenBraceAfterParameterList()
{
ParseDocumentTest("@helper Foo(string foo) " + Environment.NewLine,
new MarkupBlock(
Factory.EmptyHtml(),
new HelperBlock(new HelperCodeGenerator(new LocationTagged<string>("Foo(string foo) ", 8, 0, 8), headerComplete: false),
Factory.CodeTransition(),
Factory.MetaCode("helper ").Accepts(AcceptedCharacters.None),
Factory.Code("Foo(string foo) \r\n").Hidden())),
new RazorError(
String.Format(RazorResources.ParseError_MissingCharAfterHelperParameters, "{"),
29, 1, 0));
}
[Fact]
public void ParseHelperStatementContinuesParsingHelperUntilEOF()
{
ParseDocumentTest("@helper Foo(string foo) { " + Environment.NewLine
+ " <p>Foo</p>",
new MarkupBlock(
Factory.EmptyHtml(),
new HelperBlock(new HelperCodeGenerator(new LocationTagged<string>("Foo(string foo) {", 8, 0, 8), headerComplete: true),
Factory.CodeTransition(),
Factory.MetaCode("helper ").Accepts(AcceptedCharacters.None),
Factory.Code(@"Foo(string foo) {").Hidden().Accepts(AcceptedCharacters.None),
new StatementBlock(
Factory.Code(" \r\n")
.AsStatement()
.AutoCompleteWith("}"),
new MarkupBlock(
Factory.Markup(" <p>Foo</p>").Accepts(AcceptedCharacters.None)),
Factory.EmptyCSharp().AsStatement()))),
new RazorError(
String.Format(
RazorResources.ParseError_Expected_EndOfBlock_Before_EOF,
"helper", "}", "{"),
1, 0, 1));
}
[Fact]
public void ParseHelperStatementCorrectlyParsesHelperWithEmbeddedCode()
{
ParseDocumentTest("@helper Foo(string foo) { " + Environment.NewLine
+ " <p>@foo</p>" + Environment.NewLine
+ "}",
new MarkupBlock(
Factory.EmptyHtml(),
new HelperBlock(new HelperCodeGenerator(new LocationTagged<string>("Foo(string foo) {", 8, 0, 8), headerComplete: true),
Factory.CodeTransition(),
Factory.MetaCode("helper ").Accepts(AcceptedCharacters.None),
Factory.Code(@"Foo(string foo) {").Hidden().Accepts(AcceptedCharacters.None),
new StatementBlock(
Factory.Code(" \r\n").AsStatement(),
new MarkupBlock(
Factory.Markup(" <p>"),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("foo")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
Factory.Markup("</p>\r\n").Accepts(AcceptedCharacters.None)),
Factory.EmptyCSharp().AsStatement()),
Factory.Code("}").Hidden().Accepts(AcceptedCharacters.None)),
Factory.EmptyHtml()));
}
[Fact]
public void ParseHelperStatementCorrectlyParsesHelperWithNewlinesBetweenCloseParenAndOpenBrace()
{
ParseDocumentTest("@helper Foo(string foo)" + Environment.NewLine
+ Environment.NewLine
+ Environment.NewLine
+ Environment.NewLine
+ "{ " + Environment.NewLine
+ " <p>@foo</p>" + Environment.NewLine
+ "}",
new MarkupBlock(
Factory.EmptyHtml(),
new HelperBlock(new HelperCodeGenerator(new LocationTagged<string>("Foo(string foo)\r\n\r\n\r\n\r\n{", 8, 0, 8), headerComplete: true),
Factory.CodeTransition(),
Factory.MetaCode("helper ").Accepts(AcceptedCharacters.None),
Factory.Code("Foo(string foo)\r\n\r\n\r\n\r\n{").Hidden().Accepts(AcceptedCharacters.None),
new StatementBlock(
Factory.Code(" \r\n").AsStatement(),
new MarkupBlock(
Factory.Markup(@" <p>"),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("foo")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
Factory.Markup("</p>\r\n").Accepts(AcceptedCharacters.None)),
Factory.EmptyCSharp().AsStatement()),
Factory.Code("}").Hidden().Accepts(AcceptedCharacters.None)),
Factory.EmptyHtml()));
}
[Fact]
public void ParseHelperStatementGivesWhitespaceAfterOpenBraceToMarkupInDesignMode()
{
ParseDocumentTest("@helper Foo(string foo) { " + Environment.NewLine
+ " ",
new MarkupBlock(
Factory.EmptyHtml(),
new HelperBlock(new HelperCodeGenerator(new LocationTagged<string>("Foo(string foo) {", 8, 0, 8), headerComplete: true),
Factory.CodeTransition(),
Factory.MetaCode("helper ").Accepts(AcceptedCharacters.None),
Factory.Code(@"Foo(string foo) {").Hidden().Accepts(AcceptedCharacters.None),
new StatementBlock(
Factory.Code(" \r\n ")
.AsStatement()
.AutoCompleteWith("}")))),
designTimeParser: true,
expectedErrors: new[]
{
new RazorError(
String.Format(
RazorResources.ParseError_Expected_EndOfBlock_Before_EOF,
"helper", "}", "{"),
new SourceLocation(1, 0, 1))
});
}
[Fact]
public void ParseHelperAcceptsNestedHelpersButOutputsError()
{
ParseDocumentTest(@"@helper Foo(string foo) {" + Environment.NewLine
+ " @helper Bar(string baz) {" + Environment.NewLine
+ " }" + Environment.NewLine
+ "}",
new MarkupBlock(
Factory.EmptyHtml(),
new HelperBlock(new HelperCodeGenerator(new LocationTagged<string>("Foo(string foo) {", 8, 0, 8), headerComplete: true),
Factory.CodeTransition(),
Factory.MetaCode("helper ").Accepts(AcceptedCharacters.None),
Factory.Code(@"Foo(string foo) {").Hidden().Accepts(AcceptedCharacters.None),
new StatementBlock(
Factory.Code("\r\n ").AsStatement(),
new HelperBlock(new HelperCodeGenerator(new LocationTagged<string>("Bar(string baz) {", 39, 1, 12), headerComplete: true),
Factory.CodeTransition(),
Factory.MetaCode("helper ").Accepts(AcceptedCharacters.None),
Factory.Code(@"Bar(string baz) {").Hidden().Accepts(AcceptedCharacters.None),
new StatementBlock(
Factory.Code("\r\n ").AsStatement()),
Factory.Code("}").Hidden().Accepts(AcceptedCharacters.None)),
Factory.Code("\r\n").AsStatement()),
Factory.Code("}").Hidden().Accepts(AcceptedCharacters.None)),
Factory.EmptyHtml()),
designTimeParser: true,
expectedErrors: new[]
{
new RazorError(RazorResources.ParseError_Helpers_Cannot_Be_Nested, 38, 1, 11)
});
}
}
}

View File

@ -0,0 +1,204 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Resources;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.AspNet.Razor.Text;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
{
public class CSharpImplicitExpressionTest : CsHtmlCodeParserTestBase
{
private const string TestExtraKeyword = "model";
public override ParserBase CreateCodeParser()
{
return new CSharpCodeParser();
}
[Fact]
public void NestedImplicitExpression()
{
ParseBlockTest("if (true) { @foo }",
new StatementBlock(
Factory.Code("if (true) { ").AsStatement(),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("foo")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords, acceptTrailingDot: true)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
Factory.Code(" }").AsStatement()));
}
[Fact]
public void ParseBlockAcceptsNonEnglishCharactersThatAreValidIdentifiers()
{
ImplicitExpressionTest("हळूँजद॔.", "हळूँजद॔");
}
[Fact]
public void ParseBlockOutputsZeroLengthCodeSpanIfInvalidCharacterFollowsTransition()
{
ParseBlockTest("@/",
new ExpressionBlock(
Factory.CodeTransition(),
Factory.EmptyCSharp()
.AsImplicitExpression(KeywordSet)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
new RazorError(
String.Format(RazorResources.ParseError_Unexpected_Character_At_Start_Of_CodeBlock_CS, "/"),
new SourceLocation(1, 0, 1)));
}
[Fact]
public void ParseBlockOutputsZeroLengthCodeSpanIfEOFOccursAfterTransition()
{
ParseBlockTest("@",
new ExpressionBlock(
Factory.CodeTransition(),
Factory.EmptyCSharp()
.AsImplicitExpression(KeywordSet)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
new RazorError(
RazorResources.ParseError_Unexpected_EndOfFile_At_Start_Of_CodeBlock,
new SourceLocation(1, 0, 1)));
}
[Fact]
public void ParseBlockSupportsSlashesWithinComplexImplicitExpressions()
{
ImplicitExpressionTest("DataGridColumn.Template(\"Years of Service\", e => (int)Math.Round((DateTime.Now - dt).TotalDays / 365))");
}
[Fact]
public void ParseBlockMethodParsesSingleIdentifierAsImplicitExpression()
{
ImplicitExpressionTest("foo");
}
[Fact]
public void ParseBlockMethodDoesNotAcceptSemicolonIfExpressionTerminatedByWhitespace()
{
ImplicitExpressionTest("foo ;", "foo");
}
[Fact]
public void ParseBlockMethodIgnoresSemicolonAtEndOfSimpleImplicitExpression()
{
RunTrailingSemicolonTest("foo");
}
[Fact]
public void ParseBlockMethodParsesDottedIdentifiersAsImplicitExpression()
{
ImplicitExpressionTest("foo.bar.baz");
}
[Fact]
public void ParseBlockMethodIgnoresSemicolonAtEndOfDottedIdentifiers()
{
RunTrailingSemicolonTest("foo.bar.baz");
}
[Fact]
public void ParseBlockMethodDoesNotIncludeDotAtEOFInImplicitExpression()
{
ImplicitExpressionTest("foo.bar.", "foo.bar");
}
[Fact]
public void ParseBlockMethodDoesNotIncludeDotFollowedByInvalidIdentifierCharacterInImplicitExpression()
{
ImplicitExpressionTest("foo.bar.0", "foo.bar");
ImplicitExpressionTest("foo.bar.</p>", "foo.bar");
}
[Fact]
public void ParseBlockMethodDoesNotIncludeSemicolonAfterDot()
{
ImplicitExpressionTest("foo.bar.;", "foo.bar");
}
[Fact]
public void ParseBlockMethodTerminatesAfterIdentifierUnlessFollowedByDotOrParenInImplicitExpression()
{
ImplicitExpressionTest("foo.bar</p>", "foo.bar");
}
[Fact]
public void ParseBlockProperlyParsesParenthesesAndBalancesThemInImplicitExpression()
{
ImplicitExpressionTest(@"foo().bar(""bi\""z"", 4)(""chained method; call"").baz(@""bo""""z"", '\'', () => { return 4; }, (4+5+new { foo = bar[4] }))");
}
[Fact]
public void ParseBlockProperlyParsesBracketsAndBalancesThemInImplicitExpression()
{
ImplicitExpressionTest(@"foo.bar[4 * (8 + 7)][""fo\""o""].baz");
}
[Fact]
public void ParseBlockTerminatesImplicitExpressionAtHtmlEndTag()
{
ImplicitExpressionTest("foo().bar.baz</p>zoop", "foo().bar.baz");
}
[Fact]
public void ParseBlockTerminatesImplicitExpressionAtHtmlStartTag()
{
ImplicitExpressionTest("foo().bar.baz<p>zoop", "foo().bar.baz");
}
[Fact]
public void ParseBlockTerminatesImplicitExpressionBeforeDotIfDotNotFollowedByIdentifierStartCharacter()
{
ImplicitExpressionTest("foo().bar.baz.42", "foo().bar.baz");
}
[Fact]
public void ParseBlockStopsBalancingParenthesesAtEOF()
{
ImplicitExpressionTest("foo(()", "foo(()",
acceptedCharacters: AcceptedCharacters.Any,
errors: new RazorError(String.Format(RazorResources.ParseError_Expected_CloseBracket_Before_EOF, "(", ")"), new SourceLocation(4, 0, 4)));
}
[Fact]
public void ParseBlockTerminatesImplicitExpressionIfCloseParenFollowedByAnyWhiteSpace()
{
ImplicitExpressionTest("foo.bar() (baz)", "foo.bar()");
}
[Fact]
public void ParseBlockTerminatesImplicitExpressionIfIdentifierFollowedByAnyWhiteSpace()
{
ImplicitExpressionTest("foo .bar() (baz)", "foo");
}
[Fact]
public void ParseBlockTerminatesImplicitExpressionAtLastValidPointIfDotFollowedByWhitespace()
{
ImplicitExpressionTest("foo. bar() (baz)", "foo");
}
[Fact]
public void ParseBlockOutputExpressionIfModuleTokenNotFollowedByBrace()
{
ImplicitExpressionTest("module.foo()");
}
private void RunTrailingSemicolonTest(string expr)
{
ParseBlockTest(SyntaxConstants.TransitionString + expr + ";",
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code(expr)
.AsImplicitExpression(KeywordSet)
.Accepts(AcceptedCharacters.NonWhiteSpace)
));
}
}
}

View File

@ -0,0 +1,109 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.Razor.Editor;
using Microsoft.AspNet.Razor.Generator;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
{
public class CSharpLayoutDirectiveTest : CsHtmlCodeParserTestBase
{
[Theory]
[InlineData("Layout")]
[InlineData("LAYOUT")]
[InlineData("layOut")]
[InlineData("LayOut")]
private void LayoutKeywordIsCaseSensitive(string word)
{
ParseBlockTest(word,
new ExpressionBlock(
Factory.Code(word)
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)
));
}
[Fact]
public void LayoutDirectiveAcceptsAllTextToEndOfLine()
{
ParseBlockTest("@layout Foo Bar Baz",
new DirectiveBlock(
Factory.CodeTransition(),
Factory.MetaCode("layout ").Accepts(AcceptedCharacters.None),
Factory.MetaCode("Foo Bar Baz")
.With(new SetLayoutCodeGenerator("Foo Bar Baz"))
.WithEditorHints(EditorHints.VirtualPath | EditorHints.LayoutPage)
)
);
}
[Fact]
public void LayoutDirectiveAcceptsAnyIfNoWhitespaceFollowingLayoutKeyword()
{
ParseBlockTest("@layout",
new DirectiveBlock(
Factory.CodeTransition(),
Factory.MetaCode("layout")
)
);
}
[Fact]
public void LayoutDirectiveOutputsMarkerSpanIfAnyWhitespaceAfterLayoutKeyword()
{
ParseBlockTest("@layout ",
new DirectiveBlock(
Factory.CodeTransition(),
Factory.MetaCode("layout ").Accepts(AcceptedCharacters.None),
Factory.EmptyCSharp()
.AsMetaCode()
.With(new SetLayoutCodeGenerator(String.Empty))
.WithEditorHints(EditorHints.VirtualPath | EditorHints.LayoutPage)
)
);
}
[Fact]
public void LayoutDirectiveAcceptsTrailingNewlineButDoesNotIncludeItInLayoutPath()
{
ParseBlockTest("@layout Foo" + Environment.NewLine,
new DirectiveBlock(
Factory.CodeTransition(),
Factory.MetaCode("layout ").Accepts(AcceptedCharacters.None),
Factory.MetaCode("Foo\r\n")
.With(new SetLayoutCodeGenerator("Foo"))
.Accepts(AcceptedCharacters.None)
.WithEditorHints(EditorHints.VirtualPath | EditorHints.LayoutPage)
)
);
}
[Fact]
public void LayoutDirectiveCorrectlyRestoresContextAfterCompleting()
{
ParseDocumentTest("@layout Foo" + Environment.NewLine
+ "@foo",
new MarkupBlock(
Factory.EmptyHtml(),
new DirectiveBlock(
Factory.CodeTransition(),
Factory.MetaCode("layout ").Accepts(AcceptedCharacters.None),
Factory.MetaCode("Foo\r\n")
.With(new SetLayoutCodeGenerator("Foo"))
.Accepts(AcceptedCharacters.None)
.WithEditorHints(EditorHints.VirtualPath | EditorHints.LayoutPage)
),
Factory.EmptyHtml(),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("foo")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords, acceptTrailingDot: false)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
Factory.EmptyHtml()));
}
}
}

View File

@ -0,0 +1,102 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using Microsoft.AspNet.Razor.Generator;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
{
public class CSharpNestedStatementsTest : CsHtmlCodeParserTestBase
{
[Fact]
public void NestedSimpleStatement()
{
ParseBlockTest("@while(true) { foo(); }",
new StatementBlock(
Factory.CodeTransition(),
Factory.Code("while(true) { foo(); }")
.AsStatement()
.Accepts(AcceptedCharacters.None)));
}
[Fact]
public void NestedKeywordStatement()
{
ParseBlockTest("@while(true) { for(int i = 0; i < 10; i++) { foo(); } }",
new StatementBlock(
Factory.CodeTransition(),
Factory.Code("while(true) { for(int i = 0; i < 10; i++) { foo(); } }")
.AsStatement()
.Accepts(AcceptedCharacters.None)));
}
[Fact]
public void NestedCodeBlock()
{
ParseBlockTest("@while(true) { { { { foo(); } } } }",
new StatementBlock(
Factory.CodeTransition(),
Factory.Code("while(true) { { { { foo(); } } } }")
.AsStatement()
.Accepts(AcceptedCharacters.None)));
}
[Fact]
public void NestedImplicitExpression()
{
ParseBlockTest("@while(true) { @foo }",
new StatementBlock(
Factory.CodeTransition(),
Factory.Code("while(true) { ")
.AsStatement(),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("foo")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords, acceptTrailingDot: true)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
Factory.Code(" }")
.AsStatement()
.Accepts(AcceptedCharacters.None)));
}
[Fact]
public void NestedExplicitExpression()
{
ParseBlockTest("@while(true) { @(foo) }",
new StatementBlock(
Factory.CodeTransition(),
Factory.Code("while(true) { ")
.AsStatement(),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.MetaCode("(")
.Accepts(AcceptedCharacters.None),
Factory.Code("foo")
.AsExpression(),
Factory.MetaCode(")")
.Accepts(AcceptedCharacters.None)),
Factory.Code(" }")
.AsStatement()
.Accepts(AcceptedCharacters.None)));
}
[Fact]
public void NestedMarkupBlock()
{
ParseBlockTest("@while(true) { <p>Hello</p> }",
new StatementBlock(
Factory.CodeTransition(),
Factory.Code("while(true) {")
.AsStatement(),
new MarkupBlock(
Factory.Markup(" <p>Hello</p> ")
.With(new MarkupCodeGenerator())
.Accepts(AcceptedCharacters.None)),
Factory.Code("}")
.AsStatement()
.Accepts(AcceptedCharacters.None)));
}
}
}

View File

@ -0,0 +1,174 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Resources;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.AspNet.Razor.Tokenizer.Symbols;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
{
public class CSharpRazorCommentsTest : CsHtmlMarkupParserTestBase
{
[Fact]
public void UnterminatedRazorComment()
{
ParseDocumentTest("@*",
new MarkupBlock(
Factory.EmptyHtml(),
new CommentBlock(
Factory.MarkupTransition(HtmlSymbolType.RazorCommentTransition)
.Accepts(AcceptedCharacters.None),
Factory.MetaMarkup("*", HtmlSymbolType.RazorCommentStar)
.Accepts(AcceptedCharacters.None),
Factory.Span(SpanKind.Comment, new HtmlSymbol(
Factory.LocationTracker.CurrentLocation,
String.Empty,
HtmlSymbolType.Unknown))
.Accepts(AcceptedCharacters.Any))),
new RazorError(RazorResources.ParseError_RazorComment_Not_Terminated, 0, 0, 0));
}
[Fact]
public void EmptyRazorComment()
{
ParseDocumentTest("@**@",
new MarkupBlock(
Factory.EmptyHtml(),
new CommentBlock(
Factory.MarkupTransition(HtmlSymbolType.RazorCommentTransition)
.Accepts(AcceptedCharacters.None),
Factory.MetaMarkup("*", HtmlSymbolType.RazorCommentStar)
.Accepts(AcceptedCharacters.None),
Factory.Span(SpanKind.Comment, new HtmlSymbol(
Factory.LocationTracker.CurrentLocation,
String.Empty,
HtmlSymbolType.Unknown))
.Accepts(AcceptedCharacters.Any),
Factory.MetaMarkup("*", HtmlSymbolType.RazorCommentStar)
.Accepts(AcceptedCharacters.None),
Factory.MarkupTransition(HtmlSymbolType.RazorCommentTransition)
.Accepts(AcceptedCharacters.None)),
Factory.EmptyHtml()));
}
[Fact]
public void RazorCommentInImplicitExpressionMethodCall()
{
ParseDocumentTest("@foo(" + Environment.NewLine
+ "@**@" + Environment.NewLine,
new MarkupBlock(
Factory.EmptyHtml(),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("foo(\r\n")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords),
new CommentBlock(
Factory.CodeTransition(CSharpSymbolType.RazorCommentTransition)
.Accepts(AcceptedCharacters.None),
Factory.MetaCode("*", CSharpSymbolType.RazorCommentStar)
.Accepts(AcceptedCharacters.None),
Factory.Span(SpanKind.Comment, new CSharpSymbol(
Factory.LocationTracker.CurrentLocation,
String.Empty,
CSharpSymbolType.Unknown))
.Accepts(AcceptedCharacters.Any),
Factory.MetaCode("*", CSharpSymbolType.RazorCommentStar)
.Accepts(AcceptedCharacters.None),
Factory.CodeTransition(CSharpSymbolType.RazorCommentTransition)
.Accepts(AcceptedCharacters.None)),
Factory.Code("\r\n")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords))),
new RazorError(
String.Format(RazorResources.ParseError_Expected_CloseBracket_Before_EOF, "(", ")"),
4, 0, 4));
}
[Fact]
public void UnterminatedRazorCommentInImplicitExpressionMethodCall()
{
ParseDocumentTest("@foo(@*",
new MarkupBlock(
Factory.EmptyHtml(),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("foo(")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords),
new CommentBlock(
Factory.CodeTransition(CSharpSymbolType.RazorCommentTransition)
.Accepts(AcceptedCharacters.None),
Factory.MetaCode("*", CSharpSymbolType.RazorCommentStar)
.Accepts(AcceptedCharacters.None),
Factory.Span(SpanKind.Comment, new CSharpSymbol(
Factory.LocationTracker.CurrentLocation,
String.Empty,
CSharpSymbolType.Unknown))
.Accepts(AcceptedCharacters.Any)))),
new RazorError(RazorResources.ParseError_RazorComment_Not_Terminated, 5, 0, 5),
new RazorError(String.Format(RazorResources.ParseError_Expected_CloseBracket_Before_EOF, "(", ")"), 4, 0, 4));
}
[Fact]
public void RazorCommentInVerbatimBlock()
{
ParseDocumentTest("@{" + Environment.NewLine
+ " <text" + Environment.NewLine
+ " @**@" + Environment.NewLine
+ "}",
new MarkupBlock(
Factory.EmptyHtml(),
new StatementBlock(
Factory.CodeTransition(),
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.Code("\r\n").AsStatement(),
new MarkupBlock(
Factory.Markup(" "),
Factory.MarkupTransition("<text").Accepts(AcceptedCharacters.Any),
Factory.Markup("\r\n "),
new CommentBlock(
Factory.MarkupTransition(HtmlSymbolType.RazorCommentTransition)
.Accepts(AcceptedCharacters.None),
Factory.MetaMarkup("*", HtmlSymbolType.RazorCommentStar)
.Accepts(AcceptedCharacters.None),
Factory.Span(SpanKind.Comment, new HtmlSymbol(
Factory.LocationTracker.CurrentLocation,
String.Empty,
HtmlSymbolType.Unknown))
.Accepts(AcceptedCharacters.Any),
Factory.MetaMarkup("*", HtmlSymbolType.RazorCommentStar)
.Accepts(AcceptedCharacters.None),
Factory.MarkupTransition(HtmlSymbolType.RazorCommentTransition)
.Accepts(AcceptedCharacters.None)),
Factory.Markup("\r\n}")))),
new RazorError(RazorResources.ParseError_TextTagCannotContainAttributes, 8, 1, 4),
new RazorError(String.Format(RazorResources.ParseError_MissingEndTag, "text"), 8, 1, 4),
new RazorError(String.Format(RazorResources.ParseError_Expected_EndOfBlock_Before_EOF, RazorResources.BlockName_Code, "}", "{"), 1, 0, 1));
}
[Fact]
public void UnterminatedRazorCommentInVerbatimBlock()
{
ParseDocumentTest("@{@*",
new MarkupBlock(
Factory.EmptyHtml(),
new StatementBlock(
Factory.CodeTransition(),
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.EmptyCSharp()
.AsStatement(),
new CommentBlock(
Factory.CodeTransition(CSharpSymbolType.RazorCommentTransition)
.Accepts(AcceptedCharacters.None),
Factory.MetaCode("*", CSharpSymbolType.RazorCommentStar)
.Accepts(AcceptedCharacters.None),
Factory.Span(SpanKind.Comment, new CSharpSymbol(Factory.LocationTracker.CurrentLocation,
String.Empty,
CSharpSymbolType.Unknown))
.Accepts(AcceptedCharacters.Any)))),
new RazorError(RazorResources.ParseError_RazorComment_Not_Terminated, 2, 0, 2),
new RazorError(String.Format(RazorResources.ParseError_Expected_EndOfBlock_Before_EOF, RazorResources.BlockName_Code, "}", "{"), 1, 0, 1));
}
}
}

View File

@ -0,0 +1,44 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Resources;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.AspNet.Razor.Text;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
{
public class CSharpReservedWordsTest : CsHtmlCodeParserTestBase
{
[Theory]
[InlineData("namespace")]
[InlineData("class")]
public void ReservedWords(string word)
{
ParseBlockTest(word,
new DirectiveBlock(
Factory.MetaCode(word).Accepts(AcceptedCharacters.None)
),
new RazorError(String.Format(RazorResources.ParseError_ReservedWord, word), SourceLocation.Zero));
}
[Theory]
[InlineData("Namespace")]
[InlineData("Class")]
[InlineData("NAMESPACE")]
[InlineData("CLASS")]
[InlineData("nameSpace")]
[InlineData("NameSpace")]
private void ReservedWordsAreCaseSensitive(string word)
{
ParseBlockTest(word,
new ExpressionBlock(
Factory.Code(word)
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)
));
}
}
}

View File

@ -0,0 +1,405 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.Razor.Generator;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Resources;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
{
public class CSharpSectionTest : CsHtmlMarkupParserTestBase
{
[Fact]
public void ParseSectionBlockCapturesNewlineImmediatelyFollowing()
{
ParseDocumentTest("@section" + Environment.NewLine,
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionCodeGenerator(String.Empty),
Factory.CodeTransition(),
Factory.MetaCode("section\r\n"))),
new RazorError(
String.Format(
RazorResources.ParseError_Unexpected_Character_At_Section_Name_Start,
RazorResources.ErrorComponent_EndOfFile),
10, 1, 0));
}
[Fact]
public void ParseSectionBlockCapturesWhitespaceToEndOfLineInSectionStatementMissingOpenBrace()
{
ParseDocumentTest("@section Foo " + Environment.NewLine
+ " ",
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionCodeGenerator("Foo"),
Factory.CodeTransition(),
Factory.MetaCode("section Foo \r\n")),
Factory.Markup(" ")),
new RazorError(RazorResources.ParseError_MissingOpenBraceAfterSection, 12, 0, 12));
}
[Fact]
public void ParseSectionBlockCapturesWhitespaceToEndOfLineInSectionStatementMissingName()
{
ParseDocumentTest("@section " + Environment.NewLine
+ " ",
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionCodeGenerator(String.Empty),
Factory.CodeTransition(),
Factory.MetaCode("section \r\n")),
Factory.Markup(" ")),
new RazorError(
String.Format(
RazorResources.ParseError_Unexpected_Character_At_Section_Name_Start,
RazorResources.ErrorComponent_EndOfFile),
23, 1, 4));
}
[Fact]
public void ParseSectionBlockIgnoresSectionUnlessAllLowerCase()
{
ParseDocumentTest("@Section foo",
new MarkupBlock(
Factory.EmptyHtml(),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("Section")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
Factory.Markup(" foo")));
}
[Fact]
public void ParseSectionBlockReportsErrorAndTerminatesSectionBlockIfKeywordNotFollowedByIdentifierStartCharacter()
{
ParseDocumentTest("@section 9 { <p>Foo</p> }",
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionCodeGenerator(String.Empty),
Factory.CodeTransition(),
Factory.MetaCode("section ")),
Factory.Markup("9 { <p>Foo</p> }")),
new RazorError(
String.Format(
RazorResources.ParseError_Unexpected_Character_At_Section_Name_Start,
String.Format(RazorResources.ErrorComponent_Character, "9")),
9, 0, 9));
}
[Fact]
public void ParseSectionBlockReportsErrorAndTerminatesSectionBlockIfNameNotFollowedByOpenBrace()
{
ParseDocumentTest("@section foo-bar { <p>Foo</p> }",
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionCodeGenerator("foo"),
Factory.CodeTransition(),
Factory.MetaCode("section foo")),
Factory.Markup("-bar { <p>Foo</p> }")),
new RazorError(RazorResources.ParseError_MissingOpenBraceAfterSection, 12, 0, 12));
}
[Fact]
public void ParserOutputsErrorOnNestedSections()
{
ParseDocumentTest("@section foo { @section bar { <p>Foo</p> } }",
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionCodeGenerator("foo"),
Factory.CodeTransition(),
Factory.MetaCode("section foo {")
.AutoCompleteWith(null, atEndOfSpan: true),
new MarkupBlock(
Factory.Markup(" "),
new SectionBlock(new SectionCodeGenerator("bar"),
Factory.CodeTransition(),
Factory.MetaCode("section bar {")
.AutoCompleteWith(null, atEndOfSpan: true),
new MarkupBlock(
Factory.Markup(" <p>Foo</p> ")),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)),
Factory.Markup(" ")),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)),
Factory.EmptyHtml()),
new RazorError(
String.Format(
RazorResources.ParseError_Sections_Cannot_Be_Nested,
RazorResources.SectionExample_CS),
23, 0, 23));
}
[Fact]
public void ParseSectionBlockHandlesEOFAfterOpenBrace()
{
ParseDocumentTest("@section foo {",
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionCodeGenerator("foo"),
Factory.CodeTransition(),
Factory.MetaCode("section foo {")
.AutoCompleteWith("}", atEndOfSpan: true),
new MarkupBlock())),
new RazorError(
String.Format(RazorResources.ParseError_Expected_X, "}"),
14, 0, 14));
}
[Fact]
public void ParseSectionBlockHandlesUnterminatedSection()
{
ParseDocumentTest("@section foo { <p>Foo{}</p>",
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionCodeGenerator("foo"),
Factory.CodeTransition(),
Factory.MetaCode("section foo {")
.AutoCompleteWith("}", atEndOfSpan: true),
new MarkupBlock(
// Need to provide the markup span as fragments, since the parser will split the {} into separate symbols.
Factory.Markup(" <p>Foo", "{", "}", "</p>")))),
new RazorError(
String.Format(RazorResources.ParseError_Expected_X, "}"),
27, 0, 27));
}
[Fact]
public void ParseSectionBlockReportsErrorAndAcceptsWhitespaceToEndOfLineIfSectionNotFollowedByOpenBrace()
{
ParseDocumentTest("@section foo " + Environment.NewLine,
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionCodeGenerator("foo"),
Factory.CodeTransition(),
Factory.MetaCode("section foo \r\n"))),
new RazorError(RazorResources.ParseError_MissingOpenBraceAfterSection, 12, 0, 12));
}
[Fact]
public void ParseSectionBlockAcceptsOpenBraceMultipleLinesBelowSectionName()
{
ParseDocumentTest("@section foo " + Environment.NewLine
+ Environment.NewLine
+ Environment.NewLine
+ Environment.NewLine
+ Environment.NewLine
+ Environment.NewLine
+ "{" + Environment.NewLine
+ "<p>Foo</p>" + Environment.NewLine
+ "}",
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionCodeGenerator("foo"),
Factory.CodeTransition(),
Factory.MetaCode("section foo \r\n\r\n\r\n\r\n\r\n\r\n{")
.AutoCompleteWith(null, atEndOfSpan: true),
new MarkupBlock(
Factory.Markup("\r\n<p>Foo</p>\r\n")),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)),
Factory.EmptyHtml()));
}
[Fact]
public void ParseSectionBlockParsesNamedSectionCorrectly()
{
ParseDocumentTest("@section foo { <p>Foo</p> }",
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionCodeGenerator("foo"),
Factory.CodeTransition(),
Factory.MetaCode("section foo {")
.AutoCompleteWith(null, atEndOfSpan: true),
new MarkupBlock(
Factory.Markup(" <p>Foo</p> ")),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)),
Factory.EmptyHtml()));
}
[Fact]
public void ParseSectionBlockDoesNotRequireSpaceBetweenSectionNameAndOpenBrace()
{
ParseDocumentTest("@section foo{ <p>Foo</p> }",
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionCodeGenerator("foo"),
Factory.CodeTransition(),
Factory.MetaCode("section foo{")
.AutoCompleteWith(null, atEndOfSpan: true),
new MarkupBlock(
Factory.Markup(" <p>Foo</p> ")),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)),
Factory.EmptyHtml()));
}
[Fact]
public void ParseSectionBlockBalancesBraces()
{
ParseDocumentTest("@section foo { <script>(function foo() { return 1; })();</script> }",
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionCodeGenerator("foo"),
Factory.CodeTransition(),
Factory.MetaCode("section foo {")
.AutoCompleteWith(null, atEndOfSpan: true),
new MarkupBlock(
Factory.Markup(" <script>(function foo() { return 1; })();</script> ")),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)),
Factory.EmptyHtml()));
}
[Fact]
public void ParseSectionBlockAllowsBracesInCSharpExpression()
{
ParseDocumentTest("@section foo { I really want to render a close brace, so here I go: @(\"}\") }",
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionCodeGenerator("foo"),
Factory.CodeTransition(),
Factory.MetaCode("section foo {")
.AutoCompleteWith(null, atEndOfSpan: true),
new MarkupBlock(
Factory.Markup(" I really want to render a close brace, so here I go: "),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.MetaCode("(").Accepts(AcceptedCharacters.None),
Factory.Code("\"}\"").AsExpression(),
Factory.MetaCode(")").Accepts(AcceptedCharacters.None)),
Factory.Markup(" ")),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)),
Factory.EmptyHtml()));
}
[Fact]
public void SectionIsCorrectlyTerminatedWhenCloseBraceImmediatelyFollowsCodeBlock()
{
ParseDocumentTest("@section Foo {" + Environment.NewLine
+ "@if(true) {" + Environment.NewLine
+ "}" + Environment.NewLine
+ "}",
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"),
new StatementBlock(
Factory.CodeTransition(),
Factory.Code("if(true) {\r\n}\r\n").AsStatement()
)),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)),
Factory.EmptyHtml()));
}
[Fact]
public void SectionIsCorrectlyTerminatedWhenCloseBraceImmediatelyFollowsCodeBlockNoWhitespace()
{
ParseDocumentTest("@section Foo {" + Environment.NewLine
+ "@if(true) {" + Environment.NewLine
+ "}}",
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"),
new StatementBlock(
Factory.CodeTransition(),
Factory.Code("if(true) {\r\n}").AsStatement()
)),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)),
Factory.EmptyHtml()));
}
[Fact]
public void ParseSectionBlockCorrectlyTerminatesWhenCloseBraceImmediatelyFollowsMarkup()
{
ParseDocumentTest("@section foo {something}",
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionCodeGenerator("foo"),
Factory.CodeTransition(),
Factory.MetaCode("section foo {")
.AutoCompleteWith(null, atEndOfSpan: true),
new MarkupBlock(
Factory.Markup("something")),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)),
Factory.EmptyHtml()));
}
[Fact]
public void ParseSectionBlockParsesComment()
{
ParseDocumentTest("@section s {<!-- -->}",
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionCodeGenerator("s"),
Factory.CodeTransition(),
Factory.MetaCode("section s {")
.AutoCompleteWith(null, atEndOfSpan: true),
new MarkupBlock(
Factory.Markup("<!-- -->")),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)),
Factory.EmptyHtml()));
}
// This was a user reported bug (codeplex #710), the section parser wasn't handling
// comments.
[Fact]
public void ParseSectionBlockParsesCommentWithDelimiters()
{
ParseDocumentTest("@section s {<!-- > \" '-->}",
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionCodeGenerator("s"),
Factory.CodeTransition(),
Factory.MetaCode("section s {")
.AutoCompleteWith(null, atEndOfSpan: true),
new MarkupBlock(
Factory.Markup("<!-- > \" '-->")),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)),
Factory.EmptyHtml()));
}
[Fact]
public void ParseSectionBlockCommentRecoversFromUnclosedTag()
{
ParseDocumentTest(
"@section s {" + Environment.NewLine + "<a" + Environment.NewLine + "<!-- > \" '-->}",
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionCodeGenerator("s"),
Factory.CodeTransition(),
Factory.MetaCode("section s {")
.AutoCompleteWith(null, atEndOfSpan: true),
new MarkupBlock(
Factory.Markup(Environment.NewLine + "<a" + Environment.NewLine + "<!-- > \" '-->")),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)),
Factory.EmptyHtml()));
}
[Fact]
public void ParseSectionBlockParsesXmlProcessingInstruction()
{
ParseDocumentTest(
"@section s { <? xml bleh ?>}",
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionCodeGenerator("s"),
Factory.CodeTransition(),
Factory.MetaCode("section s {")
.AutoCompleteWith(null, atEndOfSpan: true),
new MarkupBlock(
Factory.Markup(" <? xml bleh ?>")),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)),
Factory.EmptyHtml()));
}
}
}

View File

@ -0,0 +1,198 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Resources;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.AspNet.Razor.Text;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
{
public class CSharpSpecialBlockTest : CsHtmlCodeParserTestBase
{
[Fact]
public void ParseInheritsStatementMarksInheritsSpanAsCanGrowIfMissingTrailingSpace()
{
ParseBlockTest("inherits",
new DirectiveBlock(
Factory.MetaCode("inherits").Accepts(AcceptedCharacters.Any)
),
new RazorError(
RazorResources.ParseError_InheritsKeyword_Must_Be_Followed_By_TypeName,
new SourceLocation(8, 0, 8)));
}
[Fact]
public void InheritsBlockAcceptsMultipleGenericArguments()
{
ParseBlockTest("inherits Foo.Bar<Biz<Qux>, string, int>.Baz",
new DirectiveBlock(
Factory.MetaCode("inherits ").Accepts(AcceptedCharacters.None),
Factory.Code("Foo.Bar<Biz<Qux>, string, int>.Baz")
.AsBaseType("Foo.Bar<Biz<Qux>, string, int>.Baz")
));
}
[Fact]
public void InheritsBlockOutputsErrorIfInheritsNotFollowedByTypeButAcceptsEntireLineAsCode()
{
ParseBlockTest("inherits " + Environment.NewLine
+ "foo",
new DirectiveBlock(
Factory.MetaCode("inherits ").Accepts(AcceptedCharacters.None),
Factory.Code(" \r\n")
.AsBaseType(String.Empty)
),
new RazorError(RazorResources.ParseError_InheritsKeyword_Must_Be_Followed_By_TypeName, 24, 0, 24));
}
[Fact]
public void NamespaceImportInsideCodeBlockCausesError()
{
ParseBlockTest("{ using Foo.Bar.Baz; var foo = bar; }",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.Code(" using Foo.Bar.Baz; var foo = bar; ").AsStatement(),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)
),
new RazorError(
RazorResources.ParseError_NamespaceImportAndTypeAlias_Cannot_Exist_Within_CodeBlock,
new SourceLocation(2, 0, 2)));
}
[Fact]
public void TypeAliasInsideCodeBlockIsNotHandledSpecially()
{
ParseBlockTest("{ using Foo = Bar.Baz; var foo = bar; }",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.Code(" using Foo = Bar.Baz; var foo = bar; ").AsStatement(),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)
),
new RazorError(
RazorResources.ParseError_NamespaceImportAndTypeAlias_Cannot_Exist_Within_CodeBlock,
new SourceLocation(2, 0, 2)));
}
[Fact]
public void Plan9FunctionsKeywordInsideCodeBlockIsNotHandledSpecially()
{
ParseBlockTest("{ functions Foo; }",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.Code(" functions Foo; ").AsStatement(),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)
));
}
[Fact]
public void NonKeywordStatementInCodeBlockIsHandledCorrectly()
{
ParseBlockTest("{" + Environment.NewLine
+ " List<dynamic> photos = gallery.Photo.ToList();" + Environment.NewLine
+ "}",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.Code("\r\n List<dynamic> photos = gallery.Photo.ToList();\r\n").AsStatement(),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)
));
}
[Fact]
public void ParseBlockBalancesBracesOutsideStringsIfFirstCharacterIsBraceAndReturnsSpanOfTypeCode()
{
// Arrange
const string code = "foo\"b}ar\" if(condition) { String.Format(\"{0}\"); } ";
// Act/Assert
ParseBlockTest("{" + code + "}",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.Code(code).AsStatement(),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)
));
}
[Fact]
public void ParseBlockBalancesParensOutsideStringsIfFirstCharacterIsParenAndReturnsSpanOfTypeExpression()
{
// Arrange
const string code = "foo\"b)ar\" if(condition) { String.Format(\"{0}\"); } ";
// Act/Assert
ParseBlockTest("(" + code + ")",
new ExpressionBlock(
Factory.MetaCode("(").Accepts(AcceptedCharacters.None),
Factory.Code(code).AsExpression(),
Factory.MetaCode(")").Accepts(AcceptedCharacters.None)
));
}
[Fact]
public void ParseBlockBalancesBracesAndOutputsContentAsClassLevelCodeSpanIfFirstIdentifierIsFunctionsKeyword()
{
const string code = " foo(); \"bar}baz\" ";
ParseBlockTest("functions {" + code + "} zoop",
new FunctionsBlock(
Factory.MetaCode("functions {").Accepts(AcceptedCharacters.None),
Factory.Code(code).AsFunctionsBody(),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)
));
}
[Fact]
public void ParseBlockDoesNoErrorRecoveryForFunctionsBlock()
{
ParseBlockTest("functions { { { { { } zoop",
new FunctionsBlock(
Factory.MetaCode("functions {").Accepts(AcceptedCharacters.None),
Factory.Code(" { { { { } zoop").AsFunctionsBody()
),
new RazorError(
String.Format(RazorResources.ParseError_Expected_EndOfBlock_Before_EOF, "functions", "}", "{"),
SourceLocation.Zero));
}
[Fact]
public void ParseBlockIgnoresFunctionsUnlessAllLowerCase()
{
ParseBlockTest("Functions { foo() }",
new ExpressionBlock(
Factory.Code("Functions")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)));
}
[Fact]
public void ParseBlockIgnoresSingleSlashAtStart()
{
ParseBlockTest("@/ foo",
new ExpressionBlock(
Factory.CodeTransition(),
Factory.EmptyCSharp()
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
new RazorError(
String.Format(RazorResources.ParseError_Unexpected_Character_At_Start_Of_CodeBlock_CS, "/"),
1, 0, 1));
}
[Fact]
public void ParseBlockTerminatesSingleLineCommentAtEndOfLine()
{
ParseBlockTest("if(!false) {" + Environment.NewLine
+ " // Foo" + Environment.NewLine
+ "\t<p>A real tag!</p>" + Environment.NewLine
+ "}",
new StatementBlock(
Factory.Code("if(!false) {\r\n // Foo\r\n").AsStatement(),
new MarkupBlock(
Factory.Markup("\t<p>A real tag!</p>\r\n")
.Accepts(AcceptedCharacters.None)),
Factory.Code("}").AsStatement()
));
}
}
}

View File

@ -0,0 +1,210 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using Microsoft.AspNet.Razor.Generator;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
{
// Basic Tests for C# Statements:
// * Basic case for each statement
// * Basic case for ALL clauses
// This class DOES NOT contain
// * Error cases
// * Tests for various types of nested statements
// * Comment tests
public class CSharpStatementTest : CsHtmlCodeParserTestBase
{
[Fact]
public void ForStatement()
{
ParseBlockTest("@for(int i = 0; i++; i < length) { foo(); }",
new StatementBlock(
Factory.CodeTransition(),
Factory.Code("for(int i = 0; i++; i < length) { foo(); }")
.AsStatement()
.Accepts(AcceptedCharacters.None)
));
}
[Fact]
public void ForEachStatement()
{
ParseBlockTest("@foreach(var foo in bar) { foo(); }",
new StatementBlock(
Factory.CodeTransition(),
Factory.Code("foreach(var foo in bar) { foo(); }")
.AsStatement()
.Accepts(AcceptedCharacters.None)
));
}
[Fact]
public void WhileStatement()
{
ParseBlockTest("@while(true) { foo(); }",
new StatementBlock(
Factory.CodeTransition(),
Factory.Code("while(true) { foo(); }")
.AsStatement()
.Accepts(AcceptedCharacters.None)
));
}
[Fact]
public void SwitchStatement()
{
ParseBlockTest("@switch(foo) { foo(); }",
new StatementBlock(
Factory.CodeTransition(),
Factory.Code("switch(foo) { foo(); }")
.AsStatement()
.Accepts(AcceptedCharacters.None)
));
}
[Fact]
public void LockStatement()
{
ParseBlockTest("@lock(baz) { foo(); }",
new StatementBlock(
Factory.CodeTransition(),
Factory.Code("lock(baz) { foo(); }")
.AsStatement()
.Accepts(AcceptedCharacters.None)
));
}
[Fact]
public void IfStatement()
{
ParseBlockTest("@if(true) { foo(); }",
new StatementBlock(
Factory.CodeTransition(),
Factory.Code("if(true) { foo(); }")
.AsStatement()
));
}
[Fact]
public void ElseIfClause()
{
ParseBlockTest("@if(true) { foo(); } else if(false) { foo(); } else if(!false) { foo(); }",
new StatementBlock(
Factory.CodeTransition(),
Factory.Code("if(true) { foo(); } else if(false) { foo(); } else if(!false) { foo(); }")
.AsStatement()
));
}
[Fact]
public void ElseClause()
{
ParseBlockTest("@if(true) { foo(); } else { foo(); }",
new StatementBlock(
Factory.CodeTransition(),
Factory.Code("if(true) { foo(); } else { foo(); }")
.AsStatement()
.Accepts(AcceptedCharacters.None)
));
}
[Fact]
public void TryStatement()
{
ParseBlockTest("@try { foo(); }",
new StatementBlock(
Factory.CodeTransition(),
Factory.Code("try { foo(); }")
.AsStatement()
));
}
[Fact]
public void CatchClause()
{
ParseBlockTest("@try { foo(); } catch(IOException ioex) { handleIO(); } catch(Exception ex) { handleOther(); }",
new StatementBlock(
Factory.CodeTransition(),
Factory.Code("try { foo(); } catch(IOException ioex) { handleIO(); } catch(Exception ex) { handleOther(); }")
.AsStatement()
));
}
[Fact]
public void FinallyClause()
{
ParseBlockTest("@try { foo(); } finally { Dispose(); }",
new StatementBlock(
Factory.CodeTransition(),
Factory.Code("try { foo(); } finally { Dispose(); }")
.AsStatement()
.Accepts(AcceptedCharacters.None)
));
}
[Fact]
public void UsingStatement()
{
ParseBlockTest("@using(var foo = new Foo()) { foo.Bar(); }",
new StatementBlock(
Factory.CodeTransition(),
Factory.Code("using(var foo = new Foo()) { foo.Bar(); }")
.AsStatement()
.Accepts(AcceptedCharacters.None)
));
}
[Fact]
public void UsingTypeAlias()
{
ParseBlockTest("@using StringDictionary = System.Collections.Generic.Dictionary<string, string>",
new DirectiveBlock(
Factory.CodeTransition(),
Factory.Code("using StringDictionary = System.Collections.Generic.Dictionary<string, string>")
.AsNamespaceImport(" StringDictionary = System.Collections.Generic.Dictionary<string, string>", 5)
.Accepts(AcceptedCharacters.AnyExceptNewline)
));
}
[Fact]
public void UsingNamespaceImport()
{
ParseBlockTest("@using System.Text.Encoding.ASCIIEncoding",
new DirectiveBlock(
Factory.CodeTransition(),
Factory.Code("using System.Text.Encoding.ASCIIEncoding")
.AsNamespaceImport(" System.Text.Encoding.ASCIIEncoding", 5)
.Accepts(AcceptedCharacters.AnyExceptNewline)
));
}
[Fact]
public void DoStatement()
{
ParseBlockTest("@do { foo(); } while(true);",
new StatementBlock(
Factory.CodeTransition(),
Factory.Code("do { foo(); } while(true);")
.AsStatement()
.Accepts(AcceptedCharacters.None)
));
}
[Fact]
public void NonBlockKeywordTreatedAsImplicitExpression()
{
ParseBlockTest("@is foo",
new ExpressionBlock(new ExpressionCodeGenerator(),
Factory.CodeTransition(),
Factory.Code("is")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)
));
}
}
}

View File

@ -0,0 +1,261 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.Razor.Editor;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Resources;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.AspNet.Razor.Text;
using Microsoft.AspNet.Razor.Tokenizer.Symbols;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
{
public class CSharpTemplateTest : CsHtmlCodeParserTestBase
{
private const string TestTemplateCode = " @<p>Foo #@item</p>";
private TemplateBlock TestTemplate()
{
return new TemplateBlock(
new MarkupBlock(
Factory.MarkupTransition(),
Factory.Markup("<p>Foo #"),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("item")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)
),
Factory.Markup("</p>").Accepts(AcceptedCharacters.None)
)
);
}
private const string TestNestedTemplateCode = " @<p>Foo #@Html.Repeat(10, @<p>@item</p>)</p>";
private TemplateBlock TestNestedTemplate()
{
return new TemplateBlock(
new MarkupBlock(
Factory.MarkupTransition(),
Factory.Markup("<p>Foo #"),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("Html.Repeat(10, ")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords),
new TemplateBlock(
new MarkupBlock(
Factory.MarkupTransition(),
Factory.Markup("<p>"),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("item")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)
),
Factory.Markup("</p>").Accepts(AcceptedCharacters.None)
)
),
Factory.Code(")")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)
),
Factory.Markup("</p>").Accepts(AcceptedCharacters.None)
)
);
}
[Fact]
public void ParseBlockHandlesSingleLineTemplate()
{
ParseBlockTest("{ var foo = @: bar" + Environment.NewLine
+ "; }",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.Code(" var foo = ").AsStatement(),
new TemplateBlock(
new MarkupBlock(
Factory.MarkupTransition(),
Factory.MetaMarkup(":", HtmlSymbolType.Colon),
Factory.Markup(" bar\r\n")
.With(new SingleLineMarkupEditHandler(CSharpLanguageCharacteristics.Instance.TokenizeString))
.Accepts(AcceptedCharacters.None)
)
),
Factory.Code("; ").AsStatement(),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)
));
}
[Fact]
public void ParseBlockHandlesSingleLineImmediatelyFollowingStatementChar()
{
ParseBlockTest("{i@: bar" + Environment.NewLine
+ "}",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.Code("i").AsStatement(),
new TemplateBlock(
new MarkupBlock(
Factory.MarkupTransition(),
Factory.MetaMarkup(":", HtmlSymbolType.Colon),
Factory.Markup(" bar\r\n")
.With(new SingleLineMarkupEditHandler(CSharpLanguageCharacteristics.Instance.TokenizeString))
.Accepts(AcceptedCharacters.None)
)
),
Factory.EmptyCSharp().AsStatement(),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)
));
}
[Fact]
public void ParseBlockHandlesSimpleTemplateInExplicitExpressionParens()
{
ParseBlockTest("(Html.Repeat(10," + TestTemplateCode + "))",
new ExpressionBlock(
Factory.MetaCode("(").Accepts(AcceptedCharacters.None),
Factory.Code("Html.Repeat(10, ").AsExpression(),
TestTemplate(),
Factory.Code(")").AsExpression(),
Factory.MetaCode(")").Accepts(AcceptedCharacters.None)
));
}
[Fact]
public void ParseBlockHandlesSimpleTemplateInImplicitExpressionParens()
{
ParseBlockTest("Html.Repeat(10," + TestTemplateCode + ")",
new ExpressionBlock(
Factory.Code("Html.Repeat(10, ")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords),
TestTemplate(),
Factory.Code(")")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)
));
}
[Fact]
public void ParseBlockHandlesTwoTemplatesInImplicitExpressionParens()
{
ParseBlockTest("Html.Repeat(10," + TestTemplateCode + "," + TestTemplateCode + ")",
new ExpressionBlock(
Factory.Code("Html.Repeat(10, ")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords),
TestTemplate(),
Factory.Code(", ")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords),
TestTemplate(),
Factory.Code(")")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords).Accepts(AcceptedCharacters.NonWhiteSpace)
));
}
[Fact]
public void ParseBlockProducesErrorButCorrectlyParsesNestedTemplateInImplicitExpressionParens()
{
ParseBlockTest("Html.Repeat(10," + TestNestedTemplateCode + ")",
new ExpressionBlock(
Factory.Code("Html.Repeat(10, ")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords),
TestNestedTemplate(),
Factory.Code(")")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)
),
GetNestedTemplateError(42));
}
[Fact]
public void ParseBlockHandlesSimpleTemplateInStatementWithinCodeBlock()
{
ParseBlockTest("foreach(foo in Bar) { Html.ExecuteTemplate(foo," + TestTemplateCode + "); }",
new StatementBlock(
Factory.Code("foreach(foo in Bar) { Html.ExecuteTemplate(foo, ").AsStatement(),
TestTemplate(),
Factory.Code("); }")
.AsStatement()
.Accepts(AcceptedCharacters.None)
));
}
[Fact]
public void ParseBlockHandlesTwoTemplatesInStatementWithinCodeBlock()
{
ParseBlockTest("foreach(foo in Bar) { Html.ExecuteTemplate(foo," + TestTemplateCode + "," + TestTemplateCode + "); }",
new StatementBlock(
Factory.Code("foreach(foo in Bar) { Html.ExecuteTemplate(foo, ").AsStatement(),
TestTemplate(),
Factory.Code(", ").AsStatement(),
TestTemplate(),
Factory.Code("); }")
.AsStatement()
.Accepts(AcceptedCharacters.None)
));
}
[Fact]
public void ParseBlockProducesErrorButCorrectlyParsesNestedTemplateInStatementWithinCodeBlock()
{
ParseBlockTest("foreach(foo in Bar) { Html.ExecuteTemplate(foo," + TestNestedTemplateCode + "); }",
new StatementBlock(
Factory.Code("foreach(foo in Bar) { Html.ExecuteTemplate(foo, ").AsStatement(),
TestNestedTemplate(),
Factory.Code("); }")
.AsStatement()
.Accepts(AcceptedCharacters.None)
),
GetNestedTemplateError(74));
}
[Fact]
public void ParseBlockHandlesSimpleTemplateInStatementWithinStatementBlock()
{
ParseBlockTest("{ var foo = bar; Html.ExecuteTemplate(foo," + TestTemplateCode + "); }",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.Code(" var foo = bar; Html.ExecuteTemplate(foo, ").AsStatement(),
TestTemplate(),
Factory.Code("); ").AsStatement(),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)
));
}
[Fact]
public void ParseBlockHandlessTwoTemplatesInStatementWithinStatementBlock()
{
ParseBlockTest("{ var foo = bar; Html.ExecuteTemplate(foo," + TestTemplateCode + "," + TestTemplateCode + "); }",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.Code(" var foo = bar; Html.ExecuteTemplate(foo, ").AsStatement(),
TestTemplate(),
Factory.Code(", ").AsStatement(),
TestTemplate(),
Factory.Code("); ").AsStatement(),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)
));
}
[Fact]
public void ParseBlockProducesErrorButCorrectlyParsesNestedTemplateInStatementWithinStatementBlock()
{
ParseBlockTest("{ var foo = bar; Html.ExecuteTemplate(foo," + TestNestedTemplateCode + "); }",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.Code(" var foo = bar; Html.ExecuteTemplate(foo, ").AsStatement(),
TestNestedTemplate(),
Factory.Code("); ").AsStatement(),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)
),
GetNestedTemplateError(69));
}
private static RazorError GetNestedTemplateError(int characterIndex)
{
return new RazorError(RazorResources.ParseError_InlineMarkup_Blocks_Cannot_Be_Nested, new SourceLocation(characterIndex, 0, characterIndex));
}
}
}

View File

@ -0,0 +1,494 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.Razor.Editor;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Resources;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.AspNet.Razor.Tokenizer.Symbols;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
{
public class CSharpToMarkupSwitchTest : CsHtmlCodeParserTestBase
{
[Fact]
public void SingleAngleBracketDoesNotCauseSwitchIfOuterBlockIsTerminated()
{
ParseBlockTest("{ List< }",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.Code(" List< ").AsStatement(),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)));
}
[Fact]
public void ParseBlockGivesSpacesToCodeOnAtTagTemplateTransitionInDesignTimeMode()
{
ParseBlockTest("Foo( @<p>Foo</p> )",
new ExpressionBlock(
Factory.Code("Foo( ")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.Any),
new TemplateBlock(
new MarkupBlock(
Factory.MarkupTransition(),
Factory.Markup("<p>Foo</p>").Accepts(AcceptedCharacters.None)
)
),
Factory.Code(" )")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)
), designTimeParser: true);
}
[Fact]
public void ParseBlockGivesSpacesToCodeOnAtColonTemplateTransitionInDesignTimeMode()
{
ParseBlockTest("Foo( " + Environment.NewLine
+ "@:<p>Foo</p> " + Environment.NewLine
+ ")",
new ExpressionBlock(
Factory.Code("Foo( \r\n").AsImplicitExpression(CSharpCodeParser.DefaultKeywords),
new TemplateBlock(
new MarkupBlock(
Factory.MarkupTransition(),
Factory.MetaMarkup(":", HtmlSymbolType.Colon),
Factory.Markup("<p>Foo</p> \r\n")
.With(new SingleLineMarkupEditHandler(CSharpLanguageCharacteristics.Instance.TokenizeString, AcceptedCharacters.None))
)
),
Factory.Code(")")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)
), designTimeParser: true);
}
[Fact]
public void ParseBlockGivesSpacesToCodeOnTagTransitionInDesignTimeMode()
{
ParseBlockTest("{" + Environment.NewLine
+ " <p>Foo</p> " + Environment.NewLine
+ "}",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.Code("\r\n ").AsStatement(),
new MarkupBlock(
Factory.Markup("<p>Foo</p>").Accepts(AcceptedCharacters.None)
),
Factory.Code(" \r\n").AsStatement(),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)
), designTimeParser: true);
}
[Fact]
public void ParseBlockGivesSpacesToCodeOnInvalidAtTagTransitionInDesignTimeMode()
{
ParseBlockTest("{" + Environment.NewLine
+ " @<p>Foo</p> " + Environment.NewLine
+ "}",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.Code("\r\n ").AsStatement(),
new MarkupBlock(
Factory.MarkupTransition(),
Factory.Markup("<p>Foo</p>").Accepts(AcceptedCharacters.None)
),
Factory.Code(" \r\n").AsStatement(),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)
), true,
new RazorError(RazorResources.ParseError_AtInCode_Must_Be_Followed_By_Colon_Paren_Or_Identifier_Start, 7, 1, 4));
}
[Fact]
public void ParseBlockGivesSpacesToCodeOnAtColonTransitionInDesignTimeMode()
{
ParseBlockTest("{" + Environment.NewLine
+ " @:<p>Foo</p> " + Environment.NewLine
+ "}",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.Code("\r\n ").AsStatement(),
new MarkupBlock(
Factory.MarkupTransition(),
Factory.MetaMarkup(":", HtmlSymbolType.Colon),
Factory.Markup("<p>Foo</p> \r\n")
.With(new SingleLineMarkupEditHandler(CSharpLanguageCharacteristics.Instance.TokenizeString, AcceptedCharacters.None))
),
Factory.EmptyCSharp().AsStatement(),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)
), designTimeParser: true);
}
[Fact]
public void ParseBlockShouldSupportSingleLineMarkupContainingStatementBlock()
{
ParseBlockTest("Repeat(10," + Environment.NewLine
+ " @: @{}" + Environment.NewLine
+ ")",
new ExpressionBlock(
Factory.Code("Repeat(10,\r\n ")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords),
new TemplateBlock(
new MarkupBlock(
Factory.MarkupTransition(),
Factory.MetaMarkup(":", HtmlSymbolType.Colon),
Factory.Markup(" ")
.With(new SingleLineMarkupEditHandler(CSharpLanguageCharacteristics.Instance.TokenizeString)),
new StatementBlock(
Factory.CodeTransition(),
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.EmptyCSharp().AsStatement(),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)
),
Factory.Markup("\r\n")
.With(new SingleLineMarkupEditHandler(CSharpLanguageCharacteristics.Instance.TokenizeString, AcceptedCharacters.None))
)
),
Factory.Code(")")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)
));
}
[Fact]
public void ParseBlockShouldSupportMarkupWithoutPreceedingWhitespace()
{
ParseBlockTest("foreach(var file in files){" + Environment.NewLine
+ Environment.NewLine
+ Environment.NewLine
+ "@:Baz" + Environment.NewLine
+ "<br/>" + Environment.NewLine
+ "<a>Foo</a>" + Environment.NewLine
+ "@:Bar" + Environment.NewLine
+ "}",
new StatementBlock(
Factory.Code("foreach(var file in files){\r\n\r\n\r\n").AsStatement(),
new MarkupBlock(
Factory.MarkupTransition(),
Factory.MetaMarkup(":", HtmlSymbolType.Colon),
Factory.Markup("Baz\r\n")
.With(new SingleLineMarkupEditHandler(CSharpLanguageCharacteristics.Instance.TokenizeString, AcceptedCharacters.None))
),
new MarkupBlock(
Factory.Markup("<br/>\r\n")
.Accepts(AcceptedCharacters.None)
),
new MarkupBlock(
Factory.Markup("<a>Foo</a>\r\n")
.Accepts(AcceptedCharacters.None)
),
new MarkupBlock(
Factory.MarkupTransition(),
Factory.MetaMarkup(":", HtmlSymbolType.Colon),
Factory.Markup("Bar\r\n")
.With(new SingleLineMarkupEditHandler(CSharpLanguageCharacteristics.Instance.TokenizeString, AcceptedCharacters.None))
),
Factory.Code("}").AsStatement().Accepts(AcceptedCharacters.None)
));
}
[Fact]
public void ParseBlockGivesAllWhitespaceOnSameLineExcludingPreceedingNewlineButIncludingTrailingNewLineToMarkup()
{
ParseBlockTest("if(foo) {" + Environment.NewLine
+ " var foo = \"After this statement there are 10 spaces\"; " + Environment.NewLine
+ " <p>" + Environment.NewLine
+ " Foo" + Environment.NewLine
+ " @bar" + Environment.NewLine
+ " </p>" + Environment.NewLine
+ " @:Hello!" + Environment.NewLine
+ " var biz = boz;" + Environment.NewLine
+ "}",
new StatementBlock(
Factory.Code("if(foo) {\r\n var foo = \"After this statement there are 10 spaces\"; \r\n").AsStatement(),
new MarkupBlock(
Factory.Markup(" <p>\r\n Foo\r\n"),
new ExpressionBlock(
Factory.Code(" ").AsStatement(),
Factory.CodeTransition(),
Factory.Code("bar").AsImplicitExpression(CSharpCodeParser.DefaultKeywords).Accepts(AcceptedCharacters.NonWhiteSpace)
),
Factory.Markup("\r\n </p>\r\n").Accepts(AcceptedCharacters.None)
),
new MarkupBlock(
Factory.Markup(" "),
Factory.MarkupTransition(),
Factory.MetaMarkup(":", HtmlSymbolType.Colon),
Factory.Markup("Hello!\r\n").With(new SingleLineMarkupEditHandler(CSharpLanguageCharacteristics.Instance.TokenizeString, AcceptedCharacters.None))
),
Factory.Code(" var biz = boz;\r\n}").AsStatement()));
}
[Fact]
public void ParseBlockAllowsMarkupInIfBodyWithBraces()
{
ParseBlockTest("if(foo) { <p>Bar</p> } else if(bar) { <p>Baz</p> } else { <p>Boz</p> }",
new StatementBlock(
Factory.Code("if(foo) {").AsStatement(),
new MarkupBlock(
Factory.Markup(" <p>Bar</p> ").Accepts(AcceptedCharacters.None)
),
Factory.Code("} else if(bar) {").AsStatement(),
new MarkupBlock(
Factory.Markup(" <p>Baz</p> ").Accepts(AcceptedCharacters.None)
),
Factory.Code("} else {").AsStatement(),
new MarkupBlock(
Factory.Markup(" <p>Boz</p> ").Accepts(AcceptedCharacters.None)
),
Factory.Code("}").AsStatement().Accepts(AcceptedCharacters.None)
));
}
[Fact]
public void ParseBlockAllowsMarkupInIfBodyWithBracesWithinCodeBlock()
{
ParseBlockTest("{ if(foo) { <p>Bar</p> } else if(bar) { <p>Baz</p> } else { <p>Boz</p> } }",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.Code(" if(foo) {").AsStatement(),
new MarkupBlock(
Factory.Markup(" <p>Bar</p> ").Accepts(AcceptedCharacters.None)
),
Factory.Code("} else if(bar) {").AsStatement(),
new MarkupBlock(
Factory.Markup(" <p>Baz</p> ").Accepts(AcceptedCharacters.None)
),
Factory.Code("} else {").AsStatement(),
new MarkupBlock(
Factory.Markup(" <p>Boz</p> ").Accepts(AcceptedCharacters.None)
),
Factory.Code("} ").AsStatement(),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)
));
}
[Fact]
public void ParseBlockSupportsMarkupInCaseAndDefaultBranchesOfSwitch()
{
// Arrange
ParseBlockTest("switch(foo) {" + Environment.NewLine
+ " case 0:" + Environment.NewLine
+ " <p>Foo</p>" + Environment.NewLine
+ " break;" + Environment.NewLine
+ " case 1:" + Environment.NewLine
+ " <p>Bar</p>" + Environment.NewLine
+ " return;" + Environment.NewLine
+ " case 2:" + Environment.NewLine
+ " {" + Environment.NewLine
+ " <p>Baz</p>" + Environment.NewLine
+ " <p>Boz</p>" + Environment.NewLine
+ " }" + Environment.NewLine
+ " default:" + Environment.NewLine
+ " <p>Biz</p>" + Environment.NewLine
+ "}",
new StatementBlock(
Factory.Code("switch(foo) {\r\n case 0:\r\n").AsStatement(),
new MarkupBlock(
Factory.Markup(" <p>Foo</p>\r\n").Accepts(AcceptedCharacters.None)
),
Factory.Code(" break;\r\n case 1:\r\n").AsStatement(),
new MarkupBlock(
Factory.Markup(" <p>Bar</p>\r\n").Accepts(AcceptedCharacters.None)
),
Factory.Code(" return;\r\n case 2:\r\n {\r\n").AsStatement(),
new MarkupBlock(
Factory.Markup(" <p>Baz</p>\r\n").Accepts(AcceptedCharacters.None)
),
new MarkupBlock(
Factory.Markup(" <p>Boz</p>\r\n").Accepts(AcceptedCharacters.None)
),
Factory.Code(" }\r\n default:\r\n").AsStatement(),
new MarkupBlock(
Factory.Markup(" <p>Biz</p>\r\n").Accepts(AcceptedCharacters.None)
),
Factory.Code("}").AsStatement().Accepts(AcceptedCharacters.None)));
}
[Fact]
public void ParseBlockSupportsMarkupInCaseAndDefaultBranchesOfSwitchInCodeBlock()
{
// Arrange
ParseBlockTest("{ switch(foo) {" + Environment.NewLine
+ " case 0:" + Environment.NewLine
+ " <p>Foo</p>" + Environment.NewLine
+ " break;" + Environment.NewLine
+ " case 1:" + Environment.NewLine
+ " <p>Bar</p>" + Environment.NewLine
+ " return;" + Environment.NewLine
+ " case 2:" + Environment.NewLine
+ " {" + Environment.NewLine
+ " <p>Baz</p>" + Environment.NewLine
+ " <p>Boz</p>" + Environment.NewLine
+ " }" + Environment.NewLine
+ " default:" + Environment.NewLine
+ " <p>Biz</p>" + Environment.NewLine
+ "} }",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.Code(" switch(foo) {\r\n case 0:\r\n").AsStatement(),
new MarkupBlock(
Factory.Markup(" <p>Foo</p>\r\n").Accepts(AcceptedCharacters.None)
),
Factory.Code(" break;\r\n case 1:\r\n").AsStatement(),
new MarkupBlock(
Factory.Markup(" <p>Bar</p>\r\n").Accepts(AcceptedCharacters.None)
),
Factory.Code(" return;\r\n case 2:\r\n {\r\n").AsStatement(),
new MarkupBlock(
Factory.Markup(" <p>Baz</p>\r\n").Accepts(AcceptedCharacters.None)
),
new MarkupBlock(
Factory.Markup(" <p>Boz</p>\r\n").Accepts(AcceptedCharacters.None)
),
Factory.Code(" }\r\n default:\r\n").AsStatement(),
new MarkupBlock(
Factory.Markup(" <p>Biz</p>\r\n").Accepts(AcceptedCharacters.None)
),
Factory.Code("} ").AsStatement(),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)));
}
[Fact]
public void ParseBlockParsesMarkupStatementOnOpenAngleBracket()
{
ParseBlockTest("for(int i = 0; i < 10; i++) { <p>Foo</p> }",
new StatementBlock(
Factory.Code("for(int i = 0; i < 10; i++) {").AsStatement(),
new MarkupBlock(
Factory.Markup(" <p>Foo</p> ").Accepts(AcceptedCharacters.None)
),
Factory.Code("}").AsStatement().Accepts(AcceptedCharacters.None)
));
}
[Fact]
public void ParseBlockParsesMarkupStatementOnOpenAngleBracketInCodeBlock()
{
ParseBlockTest("{ for(int i = 0; i < 10; i++) { <p>Foo</p> } }",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.Code(" for(int i = 0; i < 10; i++) {").AsStatement(),
new MarkupBlock(
Factory.Markup(" <p>Foo</p> ").Accepts(AcceptedCharacters.None)
),
Factory.Code("} ").AsStatement(),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)));
}
[Fact]
public void ParseBlockParsesMarkupStatementOnSwitchCharacterFollowedByColon()
{
// Arrange
ParseBlockTest("if(foo) { @:Bar" + Environment.NewLine
+ "} zoop",
new StatementBlock(
Factory.Code("if(foo) {").AsStatement(),
new MarkupBlock(
Factory.Markup(" "),
Factory.MarkupTransition(),
Factory.MetaMarkup(":", HtmlSymbolType.Colon),
Factory.Markup("Bar\r\n").With(new SingleLineMarkupEditHandler(CSharpLanguageCharacteristics.Instance.TokenizeString, AcceptedCharacters.None))
),
Factory.Code("}").AsStatement()));
}
[Fact]
public void ParseBlockParsesMarkupStatementOnSwitchCharacterFollowedByColonInCodeBlock()
{
// Arrange
ParseBlockTest("{ if(foo) { @:Bar" + Environment.NewLine
+ "} } zoop",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.Code(" if(foo) {").AsStatement(),
new MarkupBlock(
Factory.Markup(" "),
Factory.MarkupTransition(),
Factory.MetaMarkup(":", HtmlSymbolType.Colon),
Factory.Markup("Bar\r\n").Accepts(AcceptedCharacters.None)
),
Factory.Code("} ").AsStatement(),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)));
}
[Fact]
public void ParseBlockCorrectlyReturnsFromMarkupBlockWithPseudoTag()
{
ParseBlockTest("if (i > 0) { <text>;</text> }",
new StatementBlock(
Factory.Code("if (i > 0) {").AsStatement(),
new MarkupBlock(
Factory.Markup(" "),
Factory.MarkupTransition("<text>").Accepts(AcceptedCharacters.None),
Factory.Markup(";"),
Factory.MarkupTransition("</text>").Accepts(AcceptedCharacters.None),
Factory.Markup(" ").Accepts(AcceptedCharacters.None)
),
Factory.Code("}").AsStatement()));
}
[Fact]
public void ParseBlockCorrectlyReturnsFromMarkupBlockWithPseudoTagInCodeBlock()
{
ParseBlockTest("{ if (i > 0) { <text>;</text> } }",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.Code(" if (i > 0) {").AsStatement(),
new MarkupBlock(
Factory.Markup(" "),
Factory.MarkupTransition("<text>").Accepts(AcceptedCharacters.None),
Factory.Markup(";"),
Factory.MarkupTransition("</text>").Accepts(AcceptedCharacters.None),
Factory.Markup(" ").Accepts(AcceptedCharacters.None)
),
Factory.Code("} ").AsStatement(),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)));
}
[Fact]
public void ParseBlockSupportsAllKindsOfImplicitMarkupInCodeBlock()
{
ParseBlockTest("{" + Environment.NewLine
+ " if(true) {" + Environment.NewLine
+ " @:Single Line Markup" + Environment.NewLine
+ " }" + Environment.NewLine
+ " foreach (var p in Enumerable.Range(1, 10)) {" + Environment.NewLine
+ " <text>The number is @p</text>" + Environment.NewLine
+ " }" + Environment.NewLine
+ " if(!false) {" + Environment.NewLine
+ " <p>A real tag!</p>" + Environment.NewLine
+ " }" + Environment.NewLine
+ "}",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.Code("\r\n if(true) {\r\n").AsStatement(),
new MarkupBlock(
Factory.Markup(" "),
Factory.MarkupTransition(),
Factory.MetaMarkup(":", HtmlSymbolType.Colon),
Factory.Markup("Single Line Markup\r\n").With(new SingleLineMarkupEditHandler(CSharpLanguageCharacteristics.Instance.TokenizeString, AcceptedCharacters.None))
),
Factory.Code(" }\r\n foreach (var p in Enumerable.Range(1, 10)) {\r\n").AsStatement(),
new MarkupBlock(
Factory.Markup(" "),
Factory.MarkupTransition("<text>").Accepts(AcceptedCharacters.None),
Factory.Markup("The number is "),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("p").AsImplicitExpression(CSharpCodeParser.DefaultKeywords).Accepts(AcceptedCharacters.NonWhiteSpace)
),
Factory.MarkupTransition("</text>").Accepts(AcceptedCharacters.None),
Factory.Markup("\r\n").Accepts(AcceptedCharacters.None)
),
Factory.Code(" }\r\n if(!false) {\r\n").AsStatement(),
new MarkupBlock(
Factory.Markup(" <p>A real tag!</p>\r\n").Accepts(AcceptedCharacters.None)
),
Factory.Code(" }\r\n").AsStatement(),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)));
}
}
}

View File

@ -0,0 +1,121 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Resources;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.AspNet.Razor.Text;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
{
public class CSharpVerbatimBlockTest : CsHtmlCodeParserTestBase
{
private const string TestExtraKeyword = "model";
[Fact]
public void VerbatimBlock()
{
ParseBlockTest("@{ foo(); }",
new StatementBlock(
Factory.CodeTransition(),
Factory.MetaCode("{")
.Accepts(AcceptedCharacters.None),
Factory.Code(" foo(); ")
.AsStatement(),
Factory.MetaCode("}")
.Accepts(AcceptedCharacters.None)
));
}
[Fact]
public void InnerImplicitExpressionWithOnlySingleAtOutputsZeroLengthCodeSpan()
{
ParseBlockTest("{@}",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.EmptyCSharp().AsStatement(),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.EmptyCSharp().AsImplicitExpression(KeywordSet, acceptTrailingDot: true).Accepts(AcceptedCharacters.NonWhiteSpace)
),
Factory.EmptyCSharp().AsStatement(),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)),
designTimeParser: true,
expectedErrors: new[]
{
new RazorError(String.Format(RazorResources.ParseError_Unexpected_Character_At_Start_Of_CodeBlock_CS, "}"), new SourceLocation(2, 0, 2))
});
}
[Fact]
public void InnerImplicitExpressionDoesNotAcceptDotAfterAt()
{
ParseBlockTest("{@.}",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.EmptyCSharp().AsStatement(),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.EmptyCSharp().AsImplicitExpression(KeywordSet, acceptTrailingDot: true).Accepts(AcceptedCharacters.NonWhiteSpace)
),
Factory.Code(".").AsStatement(),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)),
designTimeParser: true,
expectedErrors: new[]
{
new RazorError(String.Format(RazorResources.ParseError_Unexpected_Character_At_Start_Of_CodeBlock_CS, "."), new SourceLocation(2, 0, 2))
});
}
[Fact]
public void InnerImplicitExpressionWithOnlySingleAtAcceptsSingleSpaceOrNewlineAtDesignTime()
{
ParseBlockTest("{" + Environment.NewLine
+ " @" + Environment.NewLine
+ "}",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.Code("\r\n ").AsStatement(),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.EmptyCSharp().AsImplicitExpression(KeywordSet, acceptTrailingDot: true).Accepts(AcceptedCharacters.NonWhiteSpace)
),
Factory.Code("\r\n").AsStatement(),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)),
/* designTimeParser */ true,
new RazorError(RazorResources.ParseError_Unexpected_WhiteSpace_At_Start_Of_CodeBlock_CS, 8, 1, 5));
}
[Fact]
public void InnerImplicitExpressionDoesNotAcceptTrailingNewlineInRunTimeMode()
{
ParseBlockTest("{@foo." + Environment.NewLine
+ "}",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.EmptyCSharp().AsStatement(),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("foo.").AsImplicitExpression(KeywordSet, acceptTrailingDot: true).Accepts(AcceptedCharacters.NonWhiteSpace)),
Factory.Code("\r\n").AsStatement(),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)));
}
[Fact]
public void InnerImplicitExpressionAcceptsTrailingNewlineInDesignTimeMode()
{
ParseBlockTest("{@foo." + Environment.NewLine
+ "}",
new StatementBlock(
Factory.MetaCode("{").Accepts(AcceptedCharacters.None),
Factory.EmptyCSharp().AsStatement(),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("foo.").AsImplicitExpression(KeywordSet, acceptTrailingDot: true).Accepts(AcceptedCharacters.NonWhiteSpace)),
Factory.Code("\r\n").AsStatement(),
Factory.MetaCode("}").Accepts(AcceptedCharacters.None)),
designTimeParser: true);
}
}
}

View File

@ -0,0 +1,33 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.AspNet.Razor.Tokenizer.Symbols;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
{
public class CSharpWhitespaceHandlingTest : CsHtmlMarkupParserTestBase
{
[Fact]
public void StatementBlockDoesNotAcceptTrailingNewlineIfNewlinesAreSignificantToAncestor()
{
ParseBlockTest("@: @if (true) { }" + Environment.NewLine
+ "}",
new MarkupBlock(
Factory.MarkupTransition()
.Accepts(AcceptedCharacters.None),
Factory.MetaMarkup(":", HtmlSymbolType.Colon),
Factory.Markup(" "),
new StatementBlock(
Factory.CodeTransition()
.Accepts(AcceptedCharacters.None),
Factory.Code("if (true) { }")
.AsStatement()
),
Factory.Markup("\r\n")
.Accepts(AcceptedCharacters.None)));
}
}
}

View File

@ -0,0 +1,289 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Resources;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.AspNet.Razor.Text;
using Microsoft.AspNet.Razor.Tokenizer.Symbols;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.Razor.Test.Parser.CSharp
{
public class CsHtmlDocumentTest : CsHtmlMarkupParserTestBase
{
[Fact]
public void UnterminatedBlockCommentCausesRazorError()
{
ParseDocumentTest("@* Foo Bar",
new MarkupBlock(
Factory.EmptyHtml(),
new CommentBlock(
Factory.MarkupTransition(HtmlSymbolType.RazorCommentTransition),
Factory.MetaMarkup("*", HtmlSymbolType.RazorCommentStar).Accepts(AcceptedCharacters.None),
Factory.Comment(" Foo Bar", HtmlSymbolType.RazorComment)
)
),
new RazorError(RazorResources.ParseError_RazorComment_Not_Terminated, SourceLocation.Zero));
}
[Fact]
public void BlockCommentInMarkupDocumentIsHandledCorrectly()
{
ParseDocumentTest("<ul>" + Environment.NewLine
+ " @* This is a block comment </ul> *@ foo",
new MarkupBlock(
Factory.Markup("<ul>\r\n "),
new CommentBlock(
Factory.MarkupTransition(HtmlSymbolType.RazorCommentTransition),
Factory.MetaMarkup("*", HtmlSymbolType.RazorCommentStar).Accepts(AcceptedCharacters.None),
Factory.Comment(" This is a block comment </ul> ", HtmlSymbolType.RazorComment),
Factory.MetaMarkup("*", HtmlSymbolType.RazorCommentStar).Accepts(AcceptedCharacters.None),
Factory.MarkupTransition(HtmlSymbolType.RazorCommentTransition)
),
Factory.Markup(" foo")
));
}
[Fact]
public void BlockCommentInMarkupBlockIsHandledCorrectly()
{
ParseBlockTest("<ul>" + Environment.NewLine
+ " @* This is a block comment </ul> *@ foo </ul>",
new MarkupBlock(
Factory.Markup("<ul>\r\n "),
new CommentBlock(
Factory.MarkupTransition(HtmlSymbolType.RazorCommentTransition),
Factory.MetaMarkup("*", HtmlSymbolType.RazorCommentStar).Accepts(AcceptedCharacters.None),
Factory.Comment(" This is a block comment </ul> ", HtmlSymbolType.RazorComment),
Factory.MetaMarkup("*", HtmlSymbolType.RazorCommentStar).Accepts(AcceptedCharacters.None),
Factory.MarkupTransition(HtmlSymbolType.RazorCommentTransition)
),
Factory.Markup(" foo </ul>").Accepts(AcceptedCharacters.None)
));
}
[Fact]
public void BlockCommentAtStatementStartInCodeBlockIsHandledCorrectly()
{
ParseDocumentTest("@if(Request.IsAuthenticated) {" + Environment.NewLine
+ " @* User is logged in! } *@" + Environment.NewLine
+ " Write(\"Hello friend!\");" + Environment.NewLine
+ "}",
new MarkupBlock(
Factory.EmptyHtml(),
new StatementBlock(
Factory.CodeTransition(),
Factory.Code("if(Request.IsAuthenticated) {\r\n ").AsStatement(),
new CommentBlock(
Factory.CodeTransition(CSharpSymbolType.RazorCommentTransition),
Factory.MetaCode("*", CSharpSymbolType.RazorCommentStar).Accepts(AcceptedCharacters.None),
Factory.Comment(" User is logged in! } ", CSharpSymbolType.RazorComment),
Factory.MetaCode("*", CSharpSymbolType.RazorCommentStar).Accepts(AcceptedCharacters.None),
Factory.CodeTransition(CSharpSymbolType.RazorCommentTransition)
),
Factory.Code("\r\n Write(\"Hello friend!\");\r\n}").AsStatement())));
}
[Fact]
public void BlockCommentInStatementInCodeBlockIsHandledCorrectly()
{
ParseDocumentTest("@if(Request.IsAuthenticated) {" + Environment.NewLine
+ " var foo = @* User is logged in! ; *@;" + Environment.NewLine
+ " Write(\"Hello friend!\");" + Environment.NewLine
+ "}",
new MarkupBlock(
Factory.EmptyHtml(),
new StatementBlock(
Factory.CodeTransition(),
Factory.Code("if(Request.IsAuthenticated) {\r\n var foo = ").AsStatement(),
new CommentBlock(
Factory.CodeTransition(CSharpSymbolType.RazorCommentTransition),
Factory.MetaCode("*", CSharpSymbolType.RazorCommentStar).Accepts(AcceptedCharacters.None),
Factory.Comment(" User is logged in! ; ", CSharpSymbolType.RazorComment),
Factory.MetaCode("*", CSharpSymbolType.RazorCommentStar).Accepts(AcceptedCharacters.None),
Factory.CodeTransition(CSharpSymbolType.RazorCommentTransition)
),
Factory.Code(";\r\n Write(\"Hello friend!\");\r\n}").AsStatement())));
}
[Fact]
public void BlockCommentInStringIsIgnored()
{
ParseDocumentTest("@if(Request.IsAuthenticated) {" + Environment.NewLine
+ " var foo = \"@* User is logged in! ; *\";" + Environment.NewLine
+ " Write(\"Hello friend!\");" + Environment.NewLine
+ "}",
new MarkupBlock(
Factory.EmptyHtml(),
new StatementBlock(
Factory.CodeTransition(),
Factory.Code("if(Request.IsAuthenticated) {" + Environment.NewLine
+ " var foo = \"@* User is logged in! ; *\";" + Environment.NewLine
+ " Write(\"Hello friend!\");" + Environment.NewLine
+ "}").AsStatement())));
}
[Fact]
public void BlockCommentInCSharpBlockCommentIsIgnored()
{
ParseDocumentTest("@if(Request.IsAuthenticated) {" + Environment.NewLine
+ " var foo = /*@* User is logged in! */ *@ */;" + Environment.NewLine
+ " Write(\"Hello friend!\");" + Environment.NewLine
+ "}",
new MarkupBlock(
Factory.EmptyHtml(),
new StatementBlock(
Factory.CodeTransition(),
Factory.Code("if(Request.IsAuthenticated) {" + Environment.NewLine
+ " var foo = /*@* User is logged in! */ *@ */;" + Environment.NewLine
+ " Write(\"Hello friend!\");" + Environment.NewLine
+ "}").AsStatement())));
}
[Fact]
public void BlockCommentInCSharpLineCommentIsIgnored()
{
ParseDocumentTest("@if(Request.IsAuthenticated) {" + Environment.NewLine
+ " var foo = //@* User is logged in! */ *@;" + Environment.NewLine
+ " Write(\"Hello friend!\");" + Environment.NewLine
+ "}",
new MarkupBlock(
Factory.EmptyHtml(),
new StatementBlock(
Factory.CodeTransition(),
Factory.Code("if(Request.IsAuthenticated) {" + Environment.NewLine
+ " var foo = //@* User is logged in! */ *@;" + Environment.NewLine
+ " Write(\"Hello friend!\");" + Environment.NewLine
+ "}").AsStatement())));
}
[Fact]
public void BlockCommentInImplicitExpressionIsHandledCorrectly()
{
ParseDocumentTest("@Html.Foo@*bar*@",
new MarkupBlock(
Factory.EmptyHtml(),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("Html.Foo").AsImplicitExpression(CSharpCodeParser.DefaultKeywords).Accepts(AcceptedCharacters.NonWhiteSpace)
),
Factory.EmptyHtml(),
new CommentBlock(
Factory.MarkupTransition(HtmlSymbolType.RazorCommentTransition),
Factory.MetaMarkup("*", HtmlSymbolType.RazorCommentStar).Accepts(AcceptedCharacters.None),
Factory.Comment("bar", HtmlSymbolType.RazorComment),
Factory.MetaMarkup("*", HtmlSymbolType.RazorCommentStar).Accepts(AcceptedCharacters.None),
Factory.MarkupTransition(HtmlSymbolType.RazorCommentTransition)
),
Factory.EmptyHtml()));
}
[Fact]
public void BlockCommentAfterDotOfImplicitExpressionIsHandledCorrectly()
{
ParseDocumentTest("@Html.@*bar*@",
new MarkupBlock(
Factory.EmptyHtml(),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("Html").AsImplicitExpression(CSharpCodeParser.DefaultKeywords).Accepts(AcceptedCharacters.NonWhiteSpace)
),
Factory.Markup("."),
new CommentBlock(
Factory.MarkupTransition(HtmlSymbolType.RazorCommentTransition),
Factory.MetaMarkup("*", HtmlSymbolType.RazorCommentStar).Accepts(AcceptedCharacters.None),
Factory.Comment("bar", HtmlSymbolType.RazorComment),
Factory.MetaMarkup("*", HtmlSymbolType.RazorCommentStar).Accepts(AcceptedCharacters.None),
Factory.MarkupTransition(HtmlSymbolType.RazorCommentTransition)
),
Factory.EmptyHtml()));
}
[Fact]
public void BlockCommentInParensOfImplicitExpressionIsHandledCorrectly()
{
ParseDocumentTest("@Html.Foo(@*bar*@ 4)",
new MarkupBlock(
Factory.EmptyHtml(),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("Html.Foo(").AsImplicitExpression(CSharpCodeParser.DefaultKeywords).Accepts(AcceptedCharacters.Any),
new CommentBlock(
Factory.CodeTransition(CSharpSymbolType.RazorCommentTransition),
Factory.MetaCode("*", CSharpSymbolType.RazorCommentStar).Accepts(AcceptedCharacters.None),
Factory.Comment("bar", CSharpSymbolType.RazorComment),
Factory.MetaCode("*", CSharpSymbolType.RazorCommentStar).Accepts(AcceptedCharacters.None),
Factory.CodeTransition(CSharpSymbolType.RazorCommentTransition)
),
Factory.Code(" 4)").AsImplicitExpression(CSharpCodeParser.DefaultKeywords).Accepts(AcceptedCharacters.NonWhiteSpace)
),
Factory.EmptyHtml()));
}
[Fact]
public void BlockCommentInBracketsOfImplicitExpressionIsHandledCorrectly()
{
ParseDocumentTest("@Html.Foo[@*bar*@ 4]",
new MarkupBlock(
Factory.EmptyHtml(),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("Html.Foo[").AsImplicitExpression(CSharpCodeParser.DefaultKeywords).Accepts(AcceptedCharacters.Any),
new CommentBlock(
Factory.CodeTransition(CSharpSymbolType.RazorCommentTransition),
Factory.MetaCode("*", CSharpSymbolType.RazorCommentStar).Accepts(AcceptedCharacters.None),
Factory.Comment("bar", CSharpSymbolType.RazorComment),
Factory.MetaCode("*", CSharpSymbolType.RazorCommentStar).Accepts(AcceptedCharacters.None),
Factory.CodeTransition(CSharpSymbolType.RazorCommentTransition)
),
Factory.Code(" 4]").AsImplicitExpression(CSharpCodeParser.DefaultKeywords).Accepts(AcceptedCharacters.NonWhiteSpace)
),
Factory.EmptyHtml()));
}
[Fact]
public void BlockCommentInParensOfConditionIsHandledCorrectly()
{
ParseDocumentTest("@if(@*bar*@) {}",
new MarkupBlock(
Factory.EmptyHtml(),
new StatementBlock(
Factory.CodeTransition(),
Factory.Code("if(").AsStatement(),
new CommentBlock(
Factory.CodeTransition(CSharpSymbolType.RazorCommentTransition),
Factory.MetaCode("*", CSharpSymbolType.RazorCommentStar).Accepts(AcceptedCharacters.None),
Factory.Comment("bar", CSharpSymbolType.RazorComment),
Factory.MetaCode("*", CSharpSymbolType.RazorCommentStar).Accepts(AcceptedCharacters.None),
Factory.CodeTransition(CSharpSymbolType.RazorCommentTransition)
),
Factory.Code(") {}").AsStatement()
)));
}
[Fact]
public void BlockCommentInExplicitExpressionIsHandledCorrectly()
{
ParseDocumentTest("@(1 + @*bar*@ 1)",
new MarkupBlock(
Factory.EmptyHtml(),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.MetaCode("(").Accepts(AcceptedCharacters.None),
Factory.Code("1 + ").AsExpression(),
new CommentBlock(
Factory.CodeTransition(CSharpSymbolType.RazorCommentTransition),
Factory.MetaCode("*", CSharpSymbolType.RazorCommentStar).Accepts(AcceptedCharacters.None),
Factory.Comment("bar", CSharpSymbolType.RazorComment),
Factory.MetaCode("*", CSharpSymbolType.RazorCommentStar).Accepts(AcceptedCharacters.None),
Factory.CodeTransition(CSharpSymbolType.RazorCommentTransition)
),
Factory.Code(" 1").AsExpression(),
Factory.MetaCode(")").Accepts(AcceptedCharacters.None)
),
Factory.EmptyHtml()));
}
}
}

View File

@ -0,0 +1,165 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.Threading;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.AspNet.Razor.Text;
using Microsoft.TestCommon;
using Moq;
namespace Microsoft.AspNet.Razor.Test.Parser
{
public class CallbackParserListenerTest
{
[Fact]
public void ListenerConstructedWithSpanCallbackCallsCallbackOnEndSpan()
{
RunOnEndSpanTest(callback => new CallbackVisitor(callback));
}
[Fact]
public void ListenerConstructedWithSpanCallbackDoesNotThrowOnStartBlockEndBlockOrError()
{
// Arrange
Action<Span> spanCallback = _ => { };
CallbackVisitor listener = new CallbackVisitor(spanCallback);
// Act/Assert
listener.VisitStartBlock(new FunctionsBlock());
listener.VisitError(new RazorError("Error", SourceLocation.Zero));
listener.VisitEndBlock(new FunctionsBlock());
}
[Fact]
public void ListenerConstructedWithSpanAndErrorCallbackCallsCallbackOnEndSpan()
{
RunOnEndSpanTest(spanCallback => new CallbackVisitor(spanCallback, _ => { }));
}
[Fact]
public void ListenerConstructedWithSpanAndErrorCallbackCallsCallbackOnError()
{
RunOnErrorTest(errorCallback => new CallbackVisitor(_ => { }, errorCallback));
}
[Fact]
public void ListenerConstructedWithAllCallbacksCallsCallbackOnEndSpan()
{
RunOnEndSpanTest(spanCallback => new CallbackVisitor(spanCallback, _ => { }, _ => { }, _ => { }));
}
[Fact]
public void ListenerConstructedWithAllCallbacksCallsCallbackOnError()
{
RunOnErrorTest(errorCallback => new CallbackVisitor(_ => { }, errorCallback, _ => { }, _ => { }));
}
[Fact]
public void ListenerConstructedWithAllCallbacksCallsCallbackOnStartBlock()
{
RunOnStartBlockTest(startBlockCallback => new CallbackVisitor(_ => { }, _ => { }, startBlockCallback, _ => { }));
}
[Fact]
public void ListenerConstructedWithAllCallbacksCallsCallbackOnEndBlock()
{
RunOnEndBlockTest(endBlockCallback => new CallbackVisitor(_ => { }, _ => { }, _ => { }, endBlockCallback));
}
[Fact]
public void ListenerCallsOnEndSpanCallbackUsingSynchronizationContextIfSpecified()
{
RunSyncContextTest(new SpanBuilder().Build(),
spanCallback => new CallbackVisitor(spanCallback, _ => { }, _ => { }, _ => { }),
(listener, expected) => listener.VisitSpan(expected));
}
[Fact]
public void ListenerCallsOnStartBlockCallbackUsingSynchronizationContextIfSpecified()
{
RunSyncContextTest(BlockType.Template,
startBlockCallback => new CallbackVisitor(_ => { }, _ => { }, startBlockCallback, _ => { }),
(listener, expected) => listener.VisitStartBlock(new BlockBuilder() { Type = expected }.Build()));
}
[Fact]
public void ListenerCallsOnEndBlockCallbackUsingSynchronizationContextIfSpecified()
{
RunSyncContextTest(BlockType.Template,
endBlockCallback => new CallbackVisitor(_ => { }, _ => { }, _ => { }, endBlockCallback),
(listener, expected) => listener.VisitEndBlock(new BlockBuilder() { Type = expected }.Build()));
}
[Fact]
public void ListenerCallsOnErrorCallbackUsingSynchronizationContextIfSpecified()
{
RunSyncContextTest(new RazorError("Bar", 42, 42, 42),
errorCallback => new CallbackVisitor(_ => { }, errorCallback, _ => { }, _ => { }),
(listener, expected) => listener.VisitError(expected));
}
private static void RunSyncContextTest<T>(T expected, Func<Action<T>, CallbackVisitor> ctor, Action<CallbackVisitor, T> call)
{
// Arrange
Mock<SynchronizationContext> mockContext = new Mock<SynchronizationContext>();
mockContext.Setup(c => c.Post(It.IsAny<SendOrPostCallback>(), It.IsAny<object>()))
.Callback<SendOrPostCallback, object>((callback, state) => { callback(expected); });
// Act/Assert
RunCallbackTest<T>(default(T), callback =>
{
CallbackVisitor listener = ctor(callback);
listener.SynchronizationContext = mockContext.Object;
return listener;
}, call, (original, actual) =>
{
Assert.NotEqual(original, actual);
Assert.Equal(expected, actual);
});
}
private static void RunOnStartBlockTest(Func<Action<BlockType>, CallbackVisitor> ctor, Action<BlockType, BlockType> verifyResults = null)
{
RunCallbackTest(BlockType.Markup, ctor, (listener, expected) => listener.VisitStartBlock(new BlockBuilder() { Type = expected }.Build()), verifyResults);
}
private static void RunOnEndBlockTest(Func<Action<BlockType>, CallbackVisitor> ctor, Action<BlockType, BlockType> verifyResults = null)
{
RunCallbackTest(BlockType.Markup, ctor, (listener, expected) => listener.VisitEndBlock(new BlockBuilder() { Type = expected }.Build()), verifyResults);
}
private static void RunOnErrorTest(Func<Action<RazorError>, CallbackVisitor> ctor, Action<RazorError, RazorError> verifyResults = null)
{
RunCallbackTest(new RazorError("Foo", SourceLocation.Zero), ctor, (listener, expected) => listener.VisitError(expected), verifyResults);
}
private static void RunOnEndSpanTest(Func<Action<Span>, CallbackVisitor> ctor, Action<Span, Span> verifyResults = null)
{
RunCallbackTest(new SpanBuilder().Build(), ctor, (listener, expected) => listener.VisitSpan(expected), verifyResults);
}
private static void RunCallbackTest<T>(T expected, Func<Action<T>, CallbackVisitor> ctor, Action<CallbackVisitor, T> call, Action<T, T> verifyResults = null)
{
// Arrange
object actual = null;
Action<T> callback = t => actual = t;
CallbackVisitor listener = ctor(callback);
// Act
call(listener, expected);
// Assert
if (verifyResults == null)
{
Assert.Equal(expected, actual);
}
else
{
verifyResults(expected, (T)actual);
}
}
}
}

View File

@ -0,0 +1,303 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.Razor.Editor;
using Microsoft.AspNet.Razor.Generator;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.AspNet.Razor.Text;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.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 =
@"<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>";
// 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 Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.Razor.Editor;
using Microsoft.AspNet.Razor.Generator;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Resources;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.AspNet.Razor.Text;
using Microsoft.AspNet.Razor.Tokenizer.Symbols;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.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("@{" + Environment.NewLine
+ "<",
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("@{" + Environment.NewLine
+ "<" + Environment.NewLine
+ "</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("< " + Environment.NewLine
+ " ",
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" + Environment.NewLine
+ "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 Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using Microsoft.AspNet.Razor.Generator;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Resources;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.AspNet.Razor.Text;
using System.Web.WebPages.TestUtils;
using Microsoft.TestCommon;
using System;
namespace Microsoft.AspNet.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 {" + Environment.NewLine
+ " <html></html>" + Environment.NewLine
+ "}",
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,90 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.Razor.Generator;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Resources;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.AspNet.Razor.Text;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.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,40 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Test.Framework;
namespace Microsoft.AspNet.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 Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Resources;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.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,353 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.Razor.Editor;
using Microsoft.AspNet.Razor.Generator;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.AspNet.Razor.Text;
using Microsoft.AspNet.Razor.Tokenizer.Symbols;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.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" + Environment.NewLine
+ "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>" + Environment.NewLine
+ " @foreach(var p in Products) {" + Environment.NewLine
+ " <li>Product: @p.Name</li>" + Environment.NewLine
+ " }" + Environment.NewLine
+ " </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>" + Environment.NewLine
+ " @foreach(var p in Products) {" + Environment.NewLine
+ " <li>Product: @p.Name</li>" + Environment.NewLine
+ " }" + Environment.NewLine
+ " </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 {" + Environment.NewLine
+ " <ul>" + Environment.NewLine
+ " @foreach(var p in Products) {" + Environment.NewLine
+ " <li>Product: @p.Name</li>" + Environment.NewLine
+ " }" + Environment.NewLine
+ " </ul>" + Environment.NewLine
+ "}",
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>" + Environment.NewLine
+ " @foreach(var p in Products) {" + Environment.NewLine
+ " <li>Product: @p.Name</li>" + Environment.NewLine
+ " }" + Environment.NewLine
+ " </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,273 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.Razor.Editor;
using Microsoft.AspNet.Razor.Generator;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.AspNet.Razor.Text;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.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()));
}
}
}

View File

@ -0,0 +1,242 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.IO;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Resources;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.AspNet.Razor.Text;
using Microsoft.AspNet.Razor.Tokenizer.Symbols;
using Microsoft.TestCommon;
using Moq;
namespace Microsoft.AspNet.Razor.Test.Parser
{
public class ParserContextTest
{
[Fact]
public void ConstructorRequiresNonNullSource()
{
var codeParser = new CSharpCodeParser();
Assert.ThrowsArgumentNull(() => new ParserContext(null, codeParser, new HtmlMarkupParser(), codeParser), "source");
}
[Fact]
public void ConstructorRequiresNonNullCodeParser()
{
var codeParser = new CSharpCodeParser();
Assert.ThrowsArgumentNull(() => new ParserContext(new SeekableTextReader(TextReader.Null), null, new HtmlMarkupParser(), codeParser), "codeParser");
}
[Fact]
public void ConstructorRequiresNonNullMarkupParser()
{
var codeParser = new CSharpCodeParser();
Assert.ThrowsArgumentNull(() => new ParserContext(new SeekableTextReader(TextReader.Null), codeParser, null, codeParser), "markupParser");
}
[Fact]
public void ConstructorRequiresNonNullActiveParser()
{
Assert.ThrowsArgumentNull(() => new ParserContext(new SeekableTextReader(TextReader.Null), new CSharpCodeParser(), new HtmlMarkupParser(), null), "activeParser");
}
[Fact]
public void ConstructorThrowsIfActiveParserIsNotCodeOrMarkupParser()
{
Assert.ThrowsArgument(() => new ParserContext(new SeekableTextReader(TextReader.Null), new CSharpCodeParser(), new HtmlMarkupParser(), new CSharpCodeParser()),
"activeParser",
RazorResources.ActiveParser_Must_Be_Code_Or_Markup_Parser);
}
[Fact]
public void ConstructorAcceptsActiveParserIfIsSameAsEitherCodeOrMarkupParser()
{
var codeParser = new CSharpCodeParser();
var markupParser = new HtmlMarkupParser();
new ParserContext(new SeekableTextReader(TextReader.Null), codeParser, markupParser, codeParser);
new ParserContext(new SeekableTextReader(TextReader.Null), codeParser, markupParser, markupParser);
}
[Fact]
public void ConstructorInitializesProperties()
{
// Arrange
SeekableTextReader expectedBuffer = new SeekableTextReader(TextReader.Null);
CSharpCodeParser expectedCodeParser = new CSharpCodeParser();
HtmlMarkupParser expectedMarkupParser = new HtmlMarkupParser();
// Act
ParserContext context = new ParserContext(expectedBuffer, expectedCodeParser, expectedMarkupParser, expectedCodeParser);
// Assert
Assert.NotNull(context.Source);
Assert.Same(expectedCodeParser, context.CodeParser);
Assert.Same(expectedMarkupParser, context.MarkupParser);
Assert.Same(expectedCodeParser, context.ActiveParser);
}
[Fact]
public void CurrentCharacterReturnsCurrentCharacterInTextBuffer()
{
// Arrange
ParserContext context = SetupTestContext("bar", b => b.Read());
// Act
char actual = context.CurrentCharacter;
// Assert
Assert.Equal('a', actual);
}
[Fact]
public void CurrentCharacterReturnsNulCharacterIfTextBufferAtEOF()
{
// Arrange
ParserContext context = SetupTestContext("bar", b => b.ReadToEnd());
// Act
char actual = context.CurrentCharacter;
// Assert
Assert.Equal('\0', actual);
}
[Fact]
public void EndOfFileReturnsFalseIfTextBufferNotAtEOF()
{
// Arrange
ParserContext context = SetupTestContext("bar");
// Act/Assert
Assert.False(context.EndOfFile);
}
[Fact]
public void EndOfFileReturnsTrueIfTextBufferAtEOF()
{
// Arrange
ParserContext context = SetupTestContext("bar", b => b.ReadToEnd());
// Act/Assert
Assert.True(context.EndOfFile);
}
[Fact]
public void StartBlockCreatesNewBlock()
{
// Arrange
ParserContext context = SetupTestContext("phoo");
// Act
context.StartBlock(BlockType.Expression);
// Assert
Assert.Equal(1, context.BlockStack.Count);
Assert.Equal(BlockType.Expression, context.BlockStack.Peek().Type);
}
[Fact]
public void EndBlockAddsCurrentBlockToParentBlock()
{
// Arrange
Mock<ParserVisitor> mockListener = new Mock<ParserVisitor>();
ParserContext context = SetupTestContext("phoo");
// Act
context.StartBlock(BlockType.Expression);
context.StartBlock(BlockType.Statement);
context.EndBlock();
// Assert
Assert.Equal(1, context.BlockStack.Count);
Assert.Equal(BlockType.Expression, context.BlockStack.Peek().Type);
Assert.Equal(1, context.BlockStack.Peek().Children.Count);
Assert.Equal(BlockType.Statement, ((Block)context.BlockStack.Peek().Children[0]).Type);
}
[Fact]
public void AddSpanAddsSpanToCurrentBlockBuilder()
{
// Arrange
var factory = SpanFactory.CreateCsHtml();
Mock<ParserVisitor> mockListener = new Mock<ParserVisitor>();
ParserContext context = SetupTestContext("phoo");
SpanBuilder builder = new SpanBuilder()
{
Kind = SpanKind.Code
};
builder.Accept(new CSharpSymbol(1, 0, 1, "foo", CSharpSymbolType.Identifier));
Span added = builder.Build();
using (context.StartBlock(BlockType.Functions))
{
context.AddSpan(added);
}
BlockBuilder expected = new BlockBuilder()
{
Type = BlockType.Functions,
};
expected.Children.Add(added);
// Assert
ParserTestBase.EvaluateResults(context.CompleteParse(), expected.Build());
}
[Fact]
public void SwitchActiveParserSetsMarkupParserAsActiveIfCodeParserCurrentlyActive()
{
// Arrange
var codeParser = new CSharpCodeParser();
var markupParser = new HtmlMarkupParser();
ParserContext context = SetupTestContext("barbazbiz", b => b.Read(), codeParser, markupParser, codeParser);
Assert.Same(codeParser, context.ActiveParser);
// Act
context.SwitchActiveParser();
// Assert
Assert.Same(markupParser, context.ActiveParser);
}
[Fact]
public void SwitchActiveParserSetsCodeParserAsActiveIfMarkupParserCurrentlyActive()
{
// Arrange
var codeParser = new CSharpCodeParser();
var markupParser = new HtmlMarkupParser();
ParserContext context = SetupTestContext("barbazbiz", b => b.Read(), codeParser, markupParser, markupParser);
Assert.Same(markupParser, context.ActiveParser);
// Act
context.SwitchActiveParser();
// Assert
Assert.Same(codeParser, context.ActiveParser);
}
private ParserContext SetupTestContext(string document)
{
var codeParser = new CSharpCodeParser();
var markupParser = new HtmlMarkupParser();
return SetupTestContext(document, b => { }, codeParser, markupParser, codeParser);
}
private ParserContext SetupTestContext(string document, Action<TextReader> positioningAction)
{
var codeParser = new CSharpCodeParser();
var markupParser = new HtmlMarkupParser();
return SetupTestContext(document, positioningAction, codeParser, markupParser, codeParser);
}
private ParserContext SetupTestContext(string document, Action<TextReader> positioningAction, ParserBase codeParser, ParserBase markupParser, ParserBase activeParser)
{
ParserContext context = new ParserContext(new SeekableTextReader(new StringReader(document)), codeParser, markupParser, activeParser);
positioningAction(context.Source);
return context;
}
}
}

View File

@ -0,0 +1,83 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Generic;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.TestCommon;
using Moq;
namespace Microsoft.AspNet.Razor.Test.Parser
{
public class ParserVisitorExtensionsTest
{
[Fact]
public void VisitThrowsOnNullVisitor()
{
ParserVisitor target = null;
ParserResults results = new ParserResults(new BlockBuilder() { Type = BlockType.Comment }.Build(), new List<RazorError>());
Assert.ThrowsArgumentNull(() => target.Visit(results), "self");
}
[Fact]
public void VisitThrowsOnNullResults()
{
ParserVisitor target = new Mock<ParserVisitor>().Object;
Assert.ThrowsArgumentNull(() => target.Visit(null), "result");
}
[Fact]
public void VisitSendsDocumentToVisitor()
{
// Arrange
Mock<ParserVisitor> targetMock = new Mock<ParserVisitor>();
Block root = new BlockBuilder() { Type = BlockType.Comment }.Build();
ParserResults results = new ParserResults(root, new List<RazorError>());
// Act
targetMock.Object.Visit(results);
// Assert
targetMock.Verify(v => v.VisitBlock(root));
}
[Fact]
public void VisitSendsErrorsToVisitor()
{
// Arrange
Mock<ParserVisitor> targetMock = new Mock<ParserVisitor>();
Block root = new BlockBuilder() { Type = BlockType.Comment }.Build();
List<RazorError> errors = new List<RazorError>() {
new RazorError("Foo", 1, 0, 1),
new RazorError("Bar", 2, 0, 2)
};
ParserResults results = new ParserResults(root, errors);
// Act
targetMock.Object.Visit(results);
// Assert
targetMock.Verify(v => v.VisitError(errors[0]));
targetMock.Verify(v => v.VisitError(errors[1]));
}
[Fact]
public void VisitCallsOnCompleteWhenAllNodesHaveBeenVisited()
{
// Arrange
Mock<ParserVisitor> targetMock = new Mock<ParserVisitor>();
Block root = new BlockBuilder() { Type = BlockType.Comment }.Build();
List<RazorError> errors = new List<RazorError>() {
new RazorError("Foo", 1, 0, 1),
new RazorError("Bar", 2, 0, 2)
};
ParserResults results = new ParserResults(root, errors);
// Act
targetMock.Object.Visit(results);
// Assert
targetMock.Verify(v => v.OnComplete());
}
}
}

View File

@ -0,0 +1,638 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.AspNet.Razor.Text;
using System.Web.WebPages.TestUtils;
using Microsoft.TestCommon;
using System;
namespace Microsoft.AspNet.Razor.Test.Parser.PartialParsing
{
public class CSharpPartialParsingTest : PartialParsingTestBase<CSharpRazorCodeLanguage>
{
[Fact]
public void ImplicitExpressionAcceptsInnerInsertionsInStatementBlock()
{
// Arrange
SpanFactory factory = SpanFactory.CreateCsHtml();
StringTextBuffer changed = new StringTextBuffer("@{" + Environment.NewLine
+ " @DateTime..Now" + Environment.NewLine
+ "}");
StringTextBuffer old = new StringTextBuffer("@{" + Environment.NewLine
+ " @DateTime.Now" + Environment.NewLine
+ "}");
// Act and Assert
RunPartialParseTest(new TextChange(17, 0, old, 1, changed),
new MarkupBlock(
factory.EmptyHtml(),
new StatementBlock(
factory.CodeTransition(),
factory.MetaCode("{").Accepts(AcceptedCharacters.None),
factory.Code("\r\n ").AsStatement(),
new ExpressionBlock(
factory.CodeTransition(),
factory.Code("DateTime..Now")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords, acceptTrailingDot: true)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
factory.Code("\r\n").AsStatement(),
factory.MetaCode("}").Accepts(AcceptedCharacters.None)),
factory.EmptyHtml()));
}
[Fact]
public void ImplicitExpressionAcceptsInnerInsertions()
{
// Arrange
SpanFactory factory = SpanFactory.CreateCsHtml();
StringTextBuffer changed = new StringTextBuffer("foo @DateTime..Now baz");
StringTextBuffer old = new StringTextBuffer("foo @DateTime.Now baz");
// Act and Assert
RunPartialParseTest(new TextChange(13, 0, old, 1, changed),
new MarkupBlock(
factory.Markup("foo "),
new ExpressionBlock(
factory.CodeTransition(),
factory.Code("DateTime..Now").AsImplicitExpression(CSharpCodeParser.DefaultKeywords).Accepts(AcceptedCharacters.NonWhiteSpace)),
factory.Markup(" baz")), additionalFlags: PartialParseResult.Provisional);
}
[Fact]
public void ImplicitExpressionAcceptsDotlessCommitInsertionsInStatementBlockAfterIdentifiers()
{
SpanFactory factory = SpanFactory.CreateCsHtml();
StringTextBuffer changed = new StringTextBuffer("@{" + Environment.NewLine
+ " @DateTime." + Environment.NewLine
+ "}");
StringTextBuffer old = new StringTextBuffer("@{" + Environment.NewLine
+ " @DateTime" + Environment.NewLine
+ "}");
var textChange = new TextChange(17, 0, old, 1, changed);
TestParserManager manager = CreateParserManager();
Action<TextChange, PartialParseResult, string> applyAndVerifyPartialChange = (changeToApply, expectedResult, expectedCode) =>
{
PartialParseResult result = manager.CheckForStructureChangesAndWait(textChange);
// Assert
Assert.Equal(expectedResult, result);
Assert.Equal(1, manager.ParseCount);
ParserTestBase.EvaluateParseTree(manager.Parser.CurrentParseTree, new MarkupBlock(
factory.EmptyHtml(),
new StatementBlock(
factory.CodeTransition(),
factory.MetaCode("{").Accepts(AcceptedCharacters.None),
factory.Code("\r\n ").AsStatement(),
new ExpressionBlock(
factory.CodeTransition(),
factory.Code(expectedCode)
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords, acceptTrailingDot: true)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
factory.Code("\r\n").AsStatement(),
factory.MetaCode("}").Accepts(AcceptedCharacters.None)),
factory.EmptyHtml()));
};
manager.InitializeWithDocument(textChange.OldBuffer);
// This is the process of a dotless commit when doing "." insertions to commit intellisense changes.
applyAndVerifyPartialChange(textChange, PartialParseResult.Accepted, "DateTime.");
old = changed;
changed = new StringTextBuffer("@{" + Environment.NewLine
+ " @DateTime.." + Environment.NewLine
+ "}");
textChange = new TextChange(18, 0, old, 1, changed);
applyAndVerifyPartialChange(textChange, PartialParseResult.Accepted, "DateTime..");
old = changed;
changed = new StringTextBuffer("@{" + Environment.NewLine
+ " @DateTime.Now." + Environment.NewLine
+ "}");
textChange = new TextChange(18, 0, old, 3, changed);
applyAndVerifyPartialChange(textChange, PartialParseResult.Accepted, "DateTime.Now.");
}
[Fact]
public void ImplicitExpressionAcceptsDotlessCommitInsertionsInStatementBlock()
{
SpanFactory factory = SpanFactory.CreateCsHtml();
StringTextBuffer changed = new StringTextBuffer("@{" + Environment.NewLine
+ " @DateT." + Environment.NewLine
+ "}");
StringTextBuffer old = new StringTextBuffer("@{" + Environment.NewLine
+ " @DateT" + Environment.NewLine
+ "}");
var textChange = new TextChange(14, 0, old, 1, changed);
TestParserManager manager = CreateParserManager();
Action<TextChange, PartialParseResult, string> applyAndVerifyPartialChange = (changeToApply, expectedResult, expectedCode) =>
{
PartialParseResult result = manager.CheckForStructureChangesAndWait(textChange);
// Assert
Assert.Equal(expectedResult, result);
Assert.Equal(1, manager.ParseCount);
ParserTestBase.EvaluateParseTree(manager.Parser.CurrentParseTree, new MarkupBlock(
factory.EmptyHtml(),
new StatementBlock(
factory.CodeTransition(),
factory.MetaCode("{").Accepts(AcceptedCharacters.None),
factory.Code("\r\n ").AsStatement(),
new ExpressionBlock(
factory.CodeTransition(),
factory.Code(expectedCode)
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords, acceptTrailingDot: true)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
factory.Code("\r\n").AsStatement(),
factory.MetaCode("}").Accepts(AcceptedCharacters.None)),
factory.EmptyHtml()));
};
manager.InitializeWithDocument(textChange.OldBuffer);
// This is the process of a dotless commit when doing "." insertions to commit intellisense changes.
applyAndVerifyPartialChange(textChange, PartialParseResult.Accepted, "DateT.");
old = changed;
changed = new StringTextBuffer("@{" + Environment.NewLine
+ " @DateTime." + Environment.NewLine
+ "}");
textChange = new TextChange(14, 0, old, 3, changed);
applyAndVerifyPartialChange(textChange, PartialParseResult.Accepted, "DateTime.");
}
[Fact]
public void ImplicitExpressionProvisionallyAcceptsDotlessCommitInsertions()
{
SpanFactory factory = SpanFactory.CreateCsHtml();
var changed = new StringTextBuffer("foo @DateT. baz");
var old = new StringTextBuffer("foo @DateT baz");
var textChange = new TextChange(10, 0, old, 1, changed);
TestParserManager manager = CreateParserManager();
Action<TextChange, PartialParseResult, string> applyAndVerifyPartialChange = (changeToApply, expectedResult, expectedCode) =>
{
PartialParseResult result = manager.CheckForStructureChangesAndWait(textChange);
// Assert
Assert.Equal(expectedResult, result);
Assert.Equal(1, manager.ParseCount);
ParserTestBase.EvaluateParseTree(manager.Parser.CurrentParseTree, new MarkupBlock(
factory.Markup("foo "),
new ExpressionBlock(
factory.CodeTransition(),
factory.Code(expectedCode).AsImplicitExpression(CSharpCodeParser.DefaultKeywords).Accepts(AcceptedCharacters.NonWhiteSpace)),
factory.Markup(" baz")));
};
manager.InitializeWithDocument(textChange.OldBuffer);
// This is the process of a dotless commit when doing "." insertions to commit intellisense changes.
applyAndVerifyPartialChange(textChange, PartialParseResult.Accepted | PartialParseResult.Provisional, "DateT.");
old = changed;
changed = new StringTextBuffer("foo @DateTime. baz");
textChange = new TextChange(10, 0, old, 3, changed);
applyAndVerifyPartialChange(textChange, PartialParseResult.Accepted | PartialParseResult.Provisional, "DateTime.");
}
[Fact]
public void ImplicitExpressionProvisionallyAcceptsDotlessCommitInsertionsAfterIdentifiers()
{
SpanFactory factory = SpanFactory.CreateCsHtml();
var changed = new StringTextBuffer("foo @DateTime. baz");
var old = new StringTextBuffer("foo @DateTime baz");
var textChange = new TextChange(13, 0, old, 1, changed);
TestParserManager manager = CreateParserManager();
Action<TextChange, PartialParseResult, string> applyAndVerifyPartialChange = (changeToApply, expectedResult, expectedCode) =>
{
PartialParseResult result = manager.CheckForStructureChangesAndWait(textChange);
// Assert
Assert.Equal(expectedResult, result);
Assert.Equal(1, manager.ParseCount);
ParserTestBase.EvaluateParseTree(manager.Parser.CurrentParseTree, new MarkupBlock(
factory.Markup("foo "),
new ExpressionBlock(
factory.CodeTransition(),
factory.Code(expectedCode).AsImplicitExpression(CSharpCodeParser.DefaultKeywords).Accepts(AcceptedCharacters.NonWhiteSpace)),
factory.Markup(" baz")));
};
manager.InitializeWithDocument(textChange.OldBuffer);
// This is the process of a dotless commit when doing "." insertions to commit intellisense changes.
applyAndVerifyPartialChange(textChange, PartialParseResult.Accepted | PartialParseResult.Provisional, "DateTime.");
old = changed;
changed = new StringTextBuffer("foo @DateTime.. baz");
textChange = new TextChange(14, 0, old, 1, changed);
applyAndVerifyPartialChange(textChange, PartialParseResult.Accepted | PartialParseResult.Provisional, "DateTime..");
old = changed;
changed = new StringTextBuffer("foo @DateTime.Now. baz");
textChange = new TextChange(14, 0, old, 3, changed);
applyAndVerifyPartialChange(textChange, PartialParseResult.Accepted | PartialParseResult.Provisional, "DateTime.Now.");
}
[Fact]
public void ImplicitExpressionProvisionallyAcceptsDeleteOfIdentifierPartsIfDotRemains()
{
SpanFactory factory = SpanFactory.CreateCsHtml();
StringTextBuffer changed = new StringTextBuffer("foo @User. baz");
StringTextBuffer old = new StringTextBuffer("foo @User.Name baz");
RunPartialParseTest(new TextChange(10, 4, old, 0, changed),
new MarkupBlock(
factory.Markup("foo "),
new ExpressionBlock(
factory.CodeTransition(),
factory.Code("User.").AsImplicitExpression(CSharpCodeParser.DefaultKeywords).Accepts(AcceptedCharacters.NonWhiteSpace)),
factory.Markup(" baz")),
additionalFlags: PartialParseResult.Provisional);
}
[Fact]
public void ImplicitExpressionAcceptsDeleteOfIdentifierPartsIfSomeOfIdentifierRemains()
{
var factory = SpanFactory.CreateCsHtml();
StringTextBuffer changed = new StringTextBuffer("foo @Us baz");
StringTextBuffer old = new StringTextBuffer("foo @User baz");
RunPartialParseTest(new TextChange(7, 2, old, 0, changed),
new MarkupBlock(
factory.Markup("foo "),
new ExpressionBlock(
factory.CodeTransition(),
factory.Code("Us").AsImplicitExpression(CSharpCodeParser.DefaultKeywords).Accepts(AcceptedCharacters.NonWhiteSpace)),
factory.Markup(" baz")));
}
[Fact]
public void ImplicitExpressionProvisionallyAcceptsMultipleInsertionIfItCausesIdentifierExpansionAndTrailingDot()
{
var factory = SpanFactory.CreateCsHtml();
StringTextBuffer changed = new StringTextBuffer("foo @User. baz");
StringTextBuffer old = new StringTextBuffer("foo @U baz");
RunPartialParseTest(new TextChange(6, 0, old, 4, changed),
new MarkupBlock(
factory.Markup("foo "),
new ExpressionBlock(
factory.CodeTransition(),
factory.Code("User.").AsImplicitExpression(CSharpCodeParser.DefaultKeywords).Accepts(AcceptedCharacters.NonWhiteSpace)),
factory.Markup(" baz")),
additionalFlags: PartialParseResult.Provisional);
}
[Fact]
public void ImplicitExpressionAcceptsMultipleInsertionIfItOnlyCausesIdentifierExpansion()
{
var factory = SpanFactory.CreateCsHtml();
StringTextBuffer changed = new StringTextBuffer("foo @barbiz baz");
StringTextBuffer old = new StringTextBuffer("foo @bar baz");
RunPartialParseTest(new TextChange(8, 0, old, 3, changed),
new MarkupBlock(
factory.Markup("foo "),
new ExpressionBlock(
factory.CodeTransition(),
factory.Code("barbiz").AsImplicitExpression(CSharpCodeParser.DefaultKeywords).Accepts(AcceptedCharacters.NonWhiteSpace)),
factory.Markup(" baz")));
}
[Fact]
public void ImplicitExpressionAcceptsIdentifierExpansionAtEndOfNonWhitespaceCharacters()
{
var factory = SpanFactory.CreateCsHtml();
StringTextBuffer changed = new StringTextBuffer("@{" + Environment.NewLine
+ " @food" + Environment.NewLine
+ "}");
StringTextBuffer old = new StringTextBuffer("@{" + Environment.NewLine
+ " @foo" + Environment.NewLine
+ "}");
RunPartialParseTest(new TextChange(12, 0, old, 1, changed),
new MarkupBlock(
factory.EmptyHtml(),
new StatementBlock(
factory.CodeTransition(),
factory.MetaCode("{").Accepts(AcceptedCharacters.None),
factory.Code("\r\n ").AsStatement(),
new ExpressionBlock(
factory.CodeTransition(),
factory.Code("food")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords, acceptTrailingDot: true)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
factory.Code("\r\n").AsStatement(),
factory.MetaCode("}").Accepts(AcceptedCharacters.None)),
factory.EmptyHtml()));
}
[Fact]
public void ImplicitExpressionAcceptsIdentifierAfterDotAtEndOfNonWhitespaceCharacters()
{
var factory = SpanFactory.CreateCsHtml();
StringTextBuffer changed = new StringTextBuffer("@{" + Environment.NewLine
+ " @foo.d" + Environment.NewLine
+ "}");
StringTextBuffer old = new StringTextBuffer("@{" + Environment.NewLine
+ " @foo." + Environment.NewLine
+ "}");
RunPartialParseTest(new TextChange(13, 0, old, 1, changed),
new MarkupBlock(
factory.EmptyHtml(),
new StatementBlock(
factory.CodeTransition(),
factory.MetaCode("{").Accepts(AcceptedCharacters.None),
factory.Code("\r\n ").AsStatement(),
new ExpressionBlock(
factory.CodeTransition(),
factory.Code("foo.d")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords, acceptTrailingDot: true)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
factory.Code("\r\n").AsStatement(),
factory.MetaCode("}").Accepts(AcceptedCharacters.None)),
factory.EmptyHtml()));
}
[Fact]
public void ImplicitExpressionAcceptsDotAtEndOfNonWhitespaceCharacters()
{
var factory = SpanFactory.CreateCsHtml();
StringTextBuffer changed = new StringTextBuffer("@{" + Environment.NewLine
+ " @foo." + Environment.NewLine
+ "}");
StringTextBuffer old = new StringTextBuffer("@{" + Environment.NewLine
+ " @foo" + Environment.NewLine
+ "}");
RunPartialParseTest(new TextChange(12, 0, old, 1, changed),
new MarkupBlock(
factory.EmptyHtml(),
new StatementBlock(
factory.CodeTransition(),
factory.MetaCode("{").Accepts(AcceptedCharacters.None),
factory.Code("\r\n ").AsStatement(),
new ExpressionBlock(
factory.CodeTransition(),
factory.Code(@"foo.")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords, acceptTrailingDot: true)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
factory.Code("\r\n").AsStatement(),
factory.MetaCode("}").Accepts(AcceptedCharacters.None)),
factory.EmptyHtml()));
}
[Fact]
public void ImplicitExpressionRejectsChangeWhichWouldHaveBeenAcceptedIfLastChangeWasProvisionallyAcceptedOnDifferentSpan()
{
var factory = SpanFactory.CreateCsHtml();
// Arrange
TextChange dotTyped = new TextChange(8, 0, new StringTextBuffer("foo @foo @bar"), 1, new StringTextBuffer("foo @foo. @bar"));
TextChange charTyped = new TextChange(14, 0, new StringTextBuffer("foo @foo. @bar"), 1, new StringTextBuffer("foo @foo. @barb"));
TestParserManager manager = CreateParserManager();
manager.InitializeWithDocument(dotTyped.OldBuffer);
// Apply the dot change
Assert.Equal(PartialParseResult.Provisional | PartialParseResult.Accepted, manager.CheckForStructureChangesAndWait(dotTyped));
// Act (apply the identifier start char change)
PartialParseResult result = manager.CheckForStructureChangesAndWait(charTyped);
// Assert
Assert.Equal(PartialParseResult.Rejected, result);
Assert.False(manager.Parser.LastResultProvisional, "LastResultProvisional flag should have been cleared but it was not");
ParserTestBase.EvaluateParseTree(manager.Parser.CurrentParseTree,
new MarkupBlock(
factory.Markup("foo "),
new ExpressionBlock(
factory.CodeTransition(),
factory.Code("foo")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
factory.Markup(". "),
new ExpressionBlock(
factory.CodeTransition(),
factory.Code("barb")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
factory.EmptyHtml()));
}
[Fact]
public void ImplicitExpressionAcceptsIdentifierTypedAfterDotIfLastChangeWasProvisionalAcceptanceOfDot()
{
var factory = SpanFactory.CreateCsHtml();
// Arrange
TextChange dotTyped = new TextChange(8, 0, new StringTextBuffer("foo @foo bar"), 1, new StringTextBuffer("foo @foo. bar"));
TextChange charTyped = new TextChange(9, 0, new StringTextBuffer("foo @foo. bar"), 1, new StringTextBuffer("foo @foo.b bar"));
TestParserManager manager = CreateParserManager();
manager.InitializeWithDocument(dotTyped.OldBuffer);
// Apply the dot change
Assert.Equal(PartialParseResult.Provisional | PartialParseResult.Accepted, manager.CheckForStructureChangesAndWait(dotTyped));
// Act (apply the identifier start char change)
PartialParseResult result = manager.CheckForStructureChangesAndWait(charTyped);
// Assert
Assert.Equal(PartialParseResult.Accepted, result);
Assert.False(manager.Parser.LastResultProvisional, "LastResultProvisional flag should have been cleared but it was not");
ParserTestBase.EvaluateParseTree(manager.Parser.CurrentParseTree,
new MarkupBlock(
factory.Markup("foo "),
new ExpressionBlock(
factory.CodeTransition(),
factory.Code("foo.b")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
factory.Markup(" bar")));
}
[Fact]
public void ImplicitExpressionProvisionallyAcceptsDotAfterIdentifierInMarkup()
{
var factory = SpanFactory.CreateCsHtml();
StringTextBuffer changed = new StringTextBuffer("foo @foo. bar");
StringTextBuffer old = new StringTextBuffer("foo @foo bar");
RunPartialParseTest(new TextChange(8, 0, old, 1, changed),
new MarkupBlock(
factory.Markup("foo "),
new ExpressionBlock(
factory.CodeTransition(),
factory.Code("foo.")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
factory.Markup(" bar")),
additionalFlags: PartialParseResult.Provisional);
}
[Fact]
public void ImplicitExpressionAcceptsAdditionalIdentifierCharactersIfEndOfSpanIsIdentifier()
{
var factory = SpanFactory.CreateCsHtml();
StringTextBuffer changed = new StringTextBuffer("foo @foob bar");
StringTextBuffer old = new StringTextBuffer("foo @foo bar");
RunPartialParseTest(new TextChange(8, 0, old, 1, changed),
new MarkupBlock(
factory.Markup("foo "),
new ExpressionBlock(
factory.CodeTransition(),
factory.Code("foob")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
factory.Markup(" bar")));
}
[Fact]
public void ImplicitExpressionAcceptsAdditionalIdentifierStartCharactersIfEndOfSpanIsDot()
{
var factory = SpanFactory.CreateCsHtml();
StringTextBuffer changed = new StringTextBuffer("@{@foo.b}");
StringTextBuffer old = new StringTextBuffer("@{@foo.}");
RunPartialParseTest(new TextChange(7, 0, old, 1, changed),
new MarkupBlock(
factory.EmptyHtml(),
new StatementBlock(
factory.CodeTransition(),
factory.MetaCode("{").Accepts(AcceptedCharacters.None),
factory.EmptyCSharp().AsStatement(),
new ExpressionBlock(
factory.CodeTransition(),
factory.Code("foo.b")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords, acceptTrailingDot: true)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
factory.EmptyCSharp().AsStatement(),
factory.MetaCode("}").Accepts(AcceptedCharacters.None)),
factory.EmptyHtml()));
}
[Fact]
public void ImplicitExpressionAcceptsDotIfTrailingDotsAreAllowed()
{
var factory = SpanFactory.CreateCsHtml();
StringTextBuffer changed = new StringTextBuffer("@{@foo.}");
StringTextBuffer old = new StringTextBuffer("@{@foo}");
RunPartialParseTest(new TextChange(6, 0, old, 1, changed),
new MarkupBlock(
factory.EmptyHtml(),
new StatementBlock(
factory.CodeTransition(),
factory.MetaCode("{").Accepts(AcceptedCharacters.None),
factory.EmptyCSharp().AsStatement(),
new ExpressionBlock(
factory.CodeTransition(),
factory.Code("foo.")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords, acceptTrailingDot: true)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
factory.EmptyCSharp().AsStatement(),
factory.MetaCode("}").Accepts(AcceptedCharacters.None)),
factory.EmptyHtml()));
}
[Fact]
public void ImplicitExpressionCorrectlyTriggersReparseIfIfKeywordTyped()
{
RunTypeKeywordTest("if");
}
[Fact]
public void ImplicitExpressionCorrectlyTriggersReparseIfDoKeywordTyped()
{
RunTypeKeywordTest("do");
}
[Fact]
public void ImplicitExpressionCorrectlyTriggersReparseIfTryKeywordTyped()
{
RunTypeKeywordTest("try");
}
[Fact]
public void ImplicitExpressionCorrectlyTriggersReparseIfForKeywordTyped()
{
RunTypeKeywordTest("for");
}
[Fact]
public void ImplicitExpressionCorrectlyTriggersReparseIfForEachKeywordTyped()
{
RunTypeKeywordTest("foreach");
}
[Fact]
public void ImplicitExpressionCorrectlyTriggersReparseIfWhileKeywordTyped()
{
RunTypeKeywordTest("while");
}
[Fact]
public void ImplicitExpressionCorrectlyTriggersReparseIfSwitchKeywordTyped()
{
RunTypeKeywordTest("switch");
}
[Fact]
public void ImplicitExpressionCorrectlyTriggersReparseIfLockKeywordTyped()
{
RunTypeKeywordTest("lock");
}
[Fact]
public void ImplicitExpressionCorrectlyTriggersReparseIfUsingKeywordTyped()
{
RunTypeKeywordTest("using");
}
[Fact]
public void ImplicitExpressionCorrectlyTriggersReparseIfSectionKeywordTyped()
{
RunTypeKeywordTest("section");
}
[Fact]
public void ImplicitExpressionCorrectlyTriggersReparseIfInheritsKeywordTyped()
{
RunTypeKeywordTest("inherits");
}
[Fact]
public void ImplicitExpressionCorrectlyTriggersReparseIfHelperKeywordTyped()
{
RunTypeKeywordTest("helper");
}
[Fact]
public void ImplicitExpressionCorrectlyTriggersReparseIfFunctionsKeywordTyped()
{
RunTypeKeywordTest("functions");
}
[Fact]
public void ImplicitExpressionCorrectlyTriggersReparseIfNamespaceKeywordTyped()
{
RunTypeKeywordTest("namespace");
}
[Fact]
public void ImplicitExpressionCorrectlyTriggersReparseIfClassKeywordTyped()
{
RunTypeKeywordTest("class");
}
[Fact]
public void ImplicitExpressionCorrectlyTriggersReparseIfLayoutKeywordTyped()
{
RunTypeKeywordTest("layout");
}
}
}

View File

@ -0,0 +1,114 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System.Threading;
using Microsoft.AspNet.Razor.Generator;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.AspNet.Razor.Test.Utils;
using Microsoft.AspNet.Razor.Text;
using System.Web.WebPages.TestUtils;
using Microsoft.TestCommon;
using System;
namespace Microsoft.AspNet.Razor.Test.Parser.PartialParsing
{
public abstract class PartialParsingTestBase<TLanguage>
where TLanguage : RazorCodeLanguage, new()
{
private const string TestLinePragmaFileName = "C:\\This\\Path\\Is\\Just\\For\\Line\\Pragmas.cshtml";
protected static void RunFullReparseTest(TextChange change, PartialParseResult additionalFlags = (PartialParseResult)0)
{
// Arrange
TestParserManager manager = CreateParserManager();
manager.InitializeWithDocument(change.OldBuffer);
// Act
PartialParseResult result = manager.CheckForStructureChangesAndWait(change);
// Assert
Assert.Equal(PartialParseResult.Rejected | additionalFlags, result);
Assert.Equal(2, manager.ParseCount);
}
protected static void RunPartialParseTest(TextChange change, Block newTreeRoot, PartialParseResult additionalFlags = (PartialParseResult)0)
{
// Arrange
TestParserManager manager = CreateParserManager();
manager.InitializeWithDocument(change.OldBuffer);
// Act
PartialParseResult result = manager.CheckForStructureChangesAndWait(change);
// Assert
Assert.Equal(PartialParseResult.Accepted | additionalFlags, result);
Assert.Equal(1, manager.ParseCount);
ParserTestBase.EvaluateParseTree(manager.Parser.CurrentParseTree, newTreeRoot);
}
protected static TestParserManager CreateParserManager()
{
RazorEngineHost host = CreateHost();
RazorEditorParser parser = new RazorEditorParser(host, TestLinePragmaFileName);
return new TestParserManager(parser);
}
protected static RazorEngineHost CreateHost()
{
return new RazorEngineHost(new TLanguage())
{
GeneratedClassContext = new GeneratedClassContext("Execute", "Write", "WriteLiteral", "WriteTo", "WriteLiteralTo", "Template", "DefineSection"),
DesignTimeMode = true
};
}
protected static void RunTypeKeywordTest(string keyword)
{
string before = "@" + keyword.Substring(0, keyword.Length - 1);
string after = "@" + keyword;
StringTextBuffer changed = new StringTextBuffer(after);
StringTextBuffer old = new StringTextBuffer(before);
RunFullReparseTest(new TextChange(keyword.Length, 0, old, 1, changed), additionalFlags: PartialParseResult.SpanContextChanged);
}
protected class TestParserManager
{
public RazorEditorParser Parser;
public ManualResetEventSlim ParserComplete;
public int ParseCount;
public TestParserManager(RazorEditorParser parser)
{
ParserComplete = new ManualResetEventSlim();
ParseCount = 0;
Parser = parser;
parser.DocumentParseComplete += (sender, args) =>
{
Interlocked.Increment(ref ParseCount);
ParserComplete.Set();
};
}
public void InitializeWithDocument(ITextBuffer startDocument)
{
CheckForStructureChangesAndWait(new TextChange(0, 0, new StringTextBuffer(String.Empty), startDocument.Length, startDocument));
}
public PartialParseResult CheckForStructureChangesAndWait(TextChange change)
{
PartialParseResult result = Parser.CheckForStructureChanges(change);
if (result.HasFlag(PartialParseResult.Rejected))
{
WaitForParse();
}
return result;
}
public void WaitForParse()
{
MiscUtils.DoWithTimeoutIfNotDebugging(ParserComplete.Wait); // Wait for the parse to finish
ParserComplete.Reset();
}
}
}
}

View File

@ -0,0 +1,375 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.AspNet.Razor.Text;
using System.Web.WebPages.TestUtils;
using Microsoft.TestCommon;
using System;
namespace Microsoft.AspNet.Razor.Test.Parser.PartialParsing
{
public class VBPartialParsingTest : PartialParsingTestBase<VBRazorCodeLanguage>
{
[Fact]
public void ImplicitExpressionProvisionallyAcceptsDeleteOfIdentifierPartsIfDotRemains()
{
var factory = SpanFactory.CreateVbHtml();
StringTextBuffer changed = new StringTextBuffer("foo @User. baz");
StringTextBuffer old = new StringTextBuffer("foo @User.Name baz");
RunPartialParseTest(new TextChange(10, 4, old, 0, changed),
new MarkupBlock(
factory.Markup("foo "),
new ExpressionBlock(
factory.CodeTransition(),
factory.Code("User.")
.AsImplicitExpression(VBCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
factory.Markup(" baz")),
additionalFlags: PartialParseResult.Provisional);
}
[Fact]
public void ImplicitExpressionAcceptsDeleteOfIdentifierPartsIfSomeOfIdentifierRemains()
{
var factory = SpanFactory.CreateVbHtml();
StringTextBuffer changed = new StringTextBuffer("foo @Us baz");
StringTextBuffer old = new StringTextBuffer("foo @User baz");
RunPartialParseTest(new TextChange(7, 2, old, 0, changed),
new MarkupBlock(
factory.Markup("foo "),
new ExpressionBlock(
factory.CodeTransition(),
factory.Code("Us")
.AsImplicitExpression(VBCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
factory.Markup(" baz")));
}
[Fact]
public void ImplicitExpressionProvisionallyAcceptsMultipleInsertionIfItCausesIdentifierExpansionAndTrailingDot()
{
var factory = SpanFactory.CreateVbHtml();
StringTextBuffer changed = new StringTextBuffer("foo @User. baz");
StringTextBuffer old = new StringTextBuffer("foo @U baz");
RunPartialParseTest(new TextChange(6, 0, old, 4, changed),
new MarkupBlock(
factory.Markup("foo "),
new ExpressionBlock(
factory.CodeTransition(),
factory.Code("User.")
.AsImplicitExpression(VBCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
factory.Markup(" baz")),
additionalFlags: PartialParseResult.Provisional);
}
[Fact]
public void ImplicitExpressionAcceptsMultipleInsertionIfItOnlyCausesIdentifierExpansion()
{
var factory = SpanFactory.CreateVbHtml();
StringTextBuffer changed = new StringTextBuffer("foo @barbiz baz");
StringTextBuffer old = new StringTextBuffer("foo @bar baz");
RunPartialParseTest(new TextChange(8, 0, old, 3, changed),
new MarkupBlock(
factory.Markup("foo "),
new ExpressionBlock(
factory.CodeTransition(),
factory.Code("barbiz")
.AsImplicitExpression(VBCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
factory.Markup(" baz")));
}
[Fact]
public void ImplicitExpressionRejectsChangeWhichWouldHaveBeenAcceptedIfLastChangeWasProvisionallyAcceptedOnDifferentSpan()
{
var factory = SpanFactory.CreateVbHtml();
// Arrange
TextChange dotTyped = new TextChange(8, 0, new StringTextBuffer("foo @foo @bar"), 1, new StringTextBuffer("foo @foo. @bar"));
TextChange charTyped = new TextChange(14, 0, new StringTextBuffer("foo @foo. @barb"), 1, new StringTextBuffer("foo @foo. @barb"));
TestParserManager manager = CreateParserManager();
manager.InitializeWithDocument(dotTyped.OldBuffer);
// Apply the dot change
Assert.Equal(PartialParseResult.Provisional | PartialParseResult.Accepted, manager.CheckForStructureChangesAndWait(dotTyped));
// Act (apply the identifier start char change)
PartialParseResult result = manager.CheckForStructureChangesAndWait(charTyped);
// Assert
Assert.Equal(PartialParseResult.Rejected, result);
Assert.False(manager.Parser.LastResultProvisional, "LastResultProvisional flag should have been cleared but it was not");
ParserTestBase.EvaluateParseTree(manager.Parser.CurrentParseTree,
new MarkupBlock(
factory.Markup("foo "),
new ExpressionBlock(
factory.CodeTransition(),
factory.Code("foo")
.AsImplicitExpression(VBCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
factory.Markup(". "),
new ExpressionBlock(
factory.CodeTransition(),
factory.Code("barb")
.AsImplicitExpression(VBCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
factory.EmptyHtml()));
}
[Fact]
public void ImplicitExpressionAcceptsIdentifierTypedAfterDotIfLastChangeWasProvisionalAcceptanceOfDot()
{
var factory = SpanFactory.CreateVbHtml();
// Arrange
TextChange dotTyped = new TextChange(8, 0, new StringTextBuffer("foo @foo bar"), 1, new StringTextBuffer("foo @foo. bar"));
TextChange charTyped = new TextChange(9, 0, new StringTextBuffer("foo @foo. bar"), 1, new StringTextBuffer("foo @foo.b bar"));
TestParserManager manager = CreateParserManager();
manager.InitializeWithDocument(dotTyped.OldBuffer);
// Apply the dot change
Assert.Equal(PartialParseResult.Provisional | PartialParseResult.Accepted, manager.CheckForStructureChangesAndWait(dotTyped));
// Act (apply the identifier start char change)
PartialParseResult result = manager.CheckForStructureChangesAndWait(charTyped);
// Assert
Assert.Equal(PartialParseResult.Accepted, result);
Assert.False(manager.Parser.LastResultProvisional, "LastResultProvisional flag should have been cleared but it was not");
ParserTestBase.EvaluateParseTree(manager.Parser.CurrentParseTree,
new MarkupBlock(
factory.Markup("foo "),
new ExpressionBlock(
factory.CodeTransition(),
factory.Code("foo.b")
.AsImplicitExpression(VBCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
factory.Markup(" bar")));
}
[Fact]
public void ImplicitExpressionAcceptsIdentifierExpansionAtEndOfNonWhitespaceCharacters()
{
var factory = SpanFactory.CreateVbHtml();
StringTextBuffer changed = new StringTextBuffer("@Code" + Environment.NewLine
+ " @food" + Environment.NewLine
+ "End Code");
StringTextBuffer old = new StringTextBuffer("@Code" + Environment.NewLine
+ " @foo" + Environment.NewLine
+ "End Code");
RunPartialParseTest(new TextChange(15, 0, old, 1, changed),
new MarkupBlock(
factory.EmptyHtml(),
new StatementBlock(
factory.CodeTransition(),
factory.MetaCode("Code")
.Accepts(AcceptedCharacters.None),
factory.Code("\r\n ").AsStatement(),
new ExpressionBlock(
factory.CodeTransition(),
factory.Code("food")
.AsImplicitExpression(VBCodeParser.DefaultKeywords, acceptTrailingDot: true)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
factory.Code("\r\n").AsStatement(),
factory.MetaCode("End Code").Accepts(AcceptedCharacters.None)),
factory.EmptyHtml()));
}
[Fact]
public void ImplicitExpressionProvisionallyAcceptsDotAfterIdentifierInMarkup()
{
var factory = SpanFactory.CreateVbHtml();
StringTextBuffer changed = new StringTextBuffer("foo @foo. bar");
StringTextBuffer old = new StringTextBuffer("foo @foo bar");
RunPartialParseTest(new TextChange(8, 0, old, 1, changed),
new MarkupBlock(
factory.Markup("foo "),
new ExpressionBlock(
factory.CodeTransition(),
factory.Code("foo.")
.AsImplicitExpression(VBCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
factory.Markup(" bar")),
additionalFlags: PartialParseResult.Provisional);
}
[Fact]
public void ImplicitExpressionAcceptsAdditionalIdentifierCharactersIfEndOfSpanIsIdentifier()
{
var factory = SpanFactory.CreateVbHtml();
StringTextBuffer changed = new StringTextBuffer("foo @foob baz");
StringTextBuffer old = new StringTextBuffer("foo @foo bar");
RunPartialParseTest(new TextChange(8, 0, old, 1, changed),
new MarkupBlock(
factory.Markup("foo "),
new ExpressionBlock(
factory.CodeTransition(),
factory.Code("foob")
.AsImplicitExpression(VBCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
factory.Markup(" bar")));
}
[Fact]
public void ImplicitExpressionAcceptsAdditionalIdentifierStartCharactersIfEndOfSpanIsDot()
{
var factory = SpanFactory.CreateVbHtml();
StringTextBuffer changed = new StringTextBuffer("@Code @foo.b End Code");
StringTextBuffer old = new StringTextBuffer("@Code @foo. End Code");
RunPartialParseTest(new TextChange(11, 0, old, 1, changed),
new MarkupBlock(
factory.EmptyHtml(),
new StatementBlock(
factory.CodeTransition(),
factory.MetaCode("Code").Accepts(AcceptedCharacters.None),
factory.Code(" ").AsStatement(),
new ExpressionBlock(
factory.CodeTransition(),
factory.Code("foo.b")
.AsImplicitExpression(VBCodeParser.DefaultKeywords, acceptTrailingDot: true)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
factory.Code(" ").AsStatement(),
factory.MetaCode("End Code").Accepts(AcceptedCharacters.None)),
factory.EmptyHtml()));
}
[Fact]
public void ImplicitExpressionAcceptsDotIfTrailingDotsAreAllowed()
{
var factory = SpanFactory.CreateVbHtml();
StringTextBuffer changed = new StringTextBuffer("@Code @foo. End Code");
StringTextBuffer old = new StringTextBuffer("@Code @foo End Code");
RunPartialParseTest(new TextChange(10, 0, old, 1, changed),
new MarkupBlock(
factory.EmptyHtml(),
new StatementBlock(
factory.CodeTransition(),
factory.MetaCode("Code").Accepts(AcceptedCharacters.None),
factory.Code(" ").AsStatement(),
new ExpressionBlock(
factory.CodeTransition(),
factory.Code("foo.")
.AsImplicitExpression(VBCodeParser.DefaultKeywords, acceptTrailingDot: true)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
factory.Code(" ").AsStatement(),
factory.MetaCode("End Code").Accepts(AcceptedCharacters.None)),
factory.EmptyHtml()));
}
[Fact]
public void ImplicitExpressionCorrectlyTriggersReparseIfFunctionsKeywordTyped()
{
RunTypeKeywordTest("functions");
}
[Fact]
public void ImplicitExpressionCorrectlyTriggersReparseIfCodeKeywordTyped()
{
RunTypeKeywordTest("code");
}
[Fact]
public void ImplicitExpressionCorrectlyTriggersReparseIfSectionKeywordTyped()
{
RunTypeKeywordTest("section");
}
[Fact]
public void ImplicitExpressionCorrectlyTriggersReparseIfDoKeywordTyped()
{
RunTypeKeywordTest("do");
}
[Fact]
public void ImplicitExpressionCorrectlyTriggersReparseIfWhileKeywordTyped()
{
RunTypeKeywordTest("while");
}
[Fact]
public void ImplicitExpressionCorrectlyTriggersReparseIfIfKeywordTyped()
{
RunTypeKeywordTest("if");
}
[Fact]
public void ImplicitExpressionCorrectlyTriggersReparseIfSelectKeywordTyped()
{
RunTypeKeywordTest("select");
}
[Fact]
public void ImplicitExpressionCorrectlyTriggersReparseIfForKeywordTyped()
{
RunTypeKeywordTest("for");
}
[Fact]
public void ImplicitExpressionCorrectlyTriggersReparseIfTryKeywordTyped()
{
RunTypeKeywordTest("try");
}
[Fact]
public void ImplicitExpressionCorrectlyTriggersReparseIfWithKeywordTyped()
{
RunTypeKeywordTest("with");
}
[Fact]
public void ImplicitExpressionCorrectlyTriggersReparseIfSyncLockKeywordTyped()
{
RunTypeKeywordTest("synclock");
}
[Fact]
public void ImplicitExpressionCorrectlyTriggersReparseIfUsingKeywordTyped()
{
RunTypeKeywordTest("using");
}
[Fact]
public void ImplicitExpressionCorrectlyTriggersReparseIfImportsKeywordTyped()
{
RunTypeKeywordTest("imports");
}
[Fact]
public void ImplicitExpressionCorrectlyTriggersReparseIfInheritsKeywordTyped()
{
RunTypeKeywordTest("inherits");
}
[Fact]
public void ImplicitExpressionCorrectlyTriggersReparseIfOptionKeywordTyped()
{
RunTypeKeywordTest("option");
}
[Fact]
public void ImplicitExpressionCorrectlyTriggersReparseIfHelperKeywordTyped()
{
RunTypeKeywordTest("helper");
}
[Fact]
public void ImplicitExpressionCorrectlyTriggersReparseIfNamespaceKeywordTyped()
{
RunTypeKeywordTest("namespace");
}
[Fact]
public void ImplicitExpressionCorrectlyTriggersReparseIfClassKeywordTyped()
{
RunTypeKeywordTest("class");
}
[Fact]
public void ImplicitExpressionCorrectlyTriggersReparseIfLayoutKeywordTyped()
{
RunTypeKeywordTest("layout");
}
}
}

View File

@ -0,0 +1,136 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.IO;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.Razor.Test.Parser
{
public class RazorParserTest
{
[Fact]
public void ConstructorRequiresNonNullCodeParser()
{
Assert.ThrowsArgumentNull(() => new RazorParser(null, new HtmlMarkupParser()), "codeParser");
}
[Fact]
public void ConstructorRequiresNonNullMarkupParser()
{
Assert.ThrowsArgumentNull(() => new RazorParser(new CSharpCodeParser(), null), "markupParser");
}
[Fact]
public void ParseMethodCallsParseDocumentOnMarkupParserAndReturnsResults()
{
var factory = SpanFactory.CreateCsHtml();
// Arrange
RazorParser parser = new RazorParser(new CSharpCodeParser(), new HtmlMarkupParser());
// Act/Assert
ParserTestBase.EvaluateResults(parser.Parse(new StringReader("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 ParseMethodUsesProvidedParserListenerIfSpecified()
{
var factory = SpanFactory.CreateCsHtml();
// Arrange
RazorParser parser = new RazorParser(new CSharpCodeParser(), new HtmlMarkupParser());
// Act
ParserResults results = parser.Parse(new StringReader("foo @bar baz"));
// Assert
ParserTestBase.EvaluateResults(results,
new MarkupBlock(
factory.Markup("foo "),
new ExpressionBlock(
factory.CodeTransition(),
factory.Code("bar")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
factory.Markup(" baz")));
}
[Fact]
public void ParseMethodSetsUpRunWithSpecifiedCodeParserMarkupParserAndListenerAndPassesToMarkupParser()
{
RunParseWithListenerTest((parser, reader) => parser.Parse(reader));
}
private static void RunParseWithListenerTest(Action<RazorParser, TextReader> parserAction)
{
// Arrange
ParserBase markupParser = new MockMarkupParser();
ParserBase codeParser = new CSharpCodeParser();
RazorParser parser = new RazorParser(codeParser, markupParser);
TextReader expectedReader = new StringReader("foo");
// Act
parserAction(parser, expectedReader);
// Assert
ParserContext actualContext = markupParser.Context;
Assert.NotNull(actualContext);
Assert.Same(markupParser, actualContext.MarkupParser);
Assert.Same(markupParser, actualContext.ActiveParser);
Assert.Same(codeParser, actualContext.CodeParser);
}
private class MockMarkupParser : ParserBase
{
public override bool IsMarkupParser
{
get
{
return true;
}
}
public override void ParseDocument()
{
using (Context.StartBlock(BlockType.Markup))
{
}
}
public override void ParseSection(Tuple<string, string> nestingSequences, bool caseSensitive = true)
{
using (Context.StartBlock(BlockType.Markup))
{
}
}
public override void ParseBlock()
{
using (Context.StartBlock(BlockType.Markup))
{
}
}
protected override ParserBase OtherParser
{
get { return Context.CodeParser; }
}
public override void BuildSpan(SpanBuilder span, Razor.Text.SourceLocation start, string content)
{
throw new NotImplementedException();
}
}
}
}

View File

@ -0,0 +1,156 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.Razor.Generator;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Resources;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.AspNet.Razor.Text;
using Microsoft.AspNet.Razor.Tokenizer.Symbols;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.Razor.Test.Parser.VB
{
public class VBAutoCompleteTest : VBHtmlCodeParserTestBase
{
[Fact]
public void FunctionsDirective_AutoComplete_At_EOF()
{
ParseBlockTest("@Functions",
new FunctionsBlock(
Factory.CodeTransition("@")
.Accepts(AcceptedCharacters.None),
Factory.MetaCode("Functions")
.Accepts(AcceptedCharacters.None),
Factory.EmptyVB()
.AsFunctionsBody()
.With(new AutoCompleteEditHandler(CSharpLanguageCharacteristics.Instance.TokenizeString)
{
AutoCompleteString = SyntaxConstants.VB.EndFunctionsKeyword
})),
new RazorError(
String.Format(RazorResources.ParseError_BlockNotTerminated, "Functions", "End Functions"),
1, 0, 1));
}
[Fact]
public void HelperDirective_AutoComplete_At_EOF()
{
ParseBlockTest("@Helper Strong(value As String)",
new HelperBlock(new HelperCodeGenerator(new LocationTagged<string>("Strong(value As String)", 8, 0, 8), headerComplete: true),
Factory.CodeTransition(),
Factory.MetaCode("Helper ")
.Accepts(AcceptedCharacters.None),
Factory.Code("Strong(value As String)")
.Hidden()
.Accepts(AcceptedCharacters.None)
.With(new AutoCompleteEditHandler(CSharpLanguageCharacteristics.Instance.TokenizeString) { AutoCompleteString = SyntaxConstants.VB.EndHelperKeyword }),
new StatementBlock()),
new RazorError(
String.Format(RazorResources.ParseError_BlockNotTerminated, "Helper", "End Helper"),
1, 0, 1));
}
[Fact]
public void SectionDirective_AutoComplete_At_EOF()
{
ParseBlockTest("@Section Header",
new SectionBlock(new SectionCodeGenerator("Header"),
Factory.CodeTransition(),
Factory.MetaCode("Section Header")
.With(new AutoCompleteEditHandler(CSharpLanguageCharacteristics.Instance.TokenizeString) { AutoCompleteString = SyntaxConstants.VB.EndSectionKeyword }),
new MarkupBlock()),
new RazorError(
String.Format(RazorResources.ParseError_BlockNotTerminated, "Section", "End Section"),
1, 0, 1));
}
[Fact]
public void VerbatimBlock_AutoComplete_At_EOF()
{
ParseBlockTest("@Code",
new StatementBlock(
Factory.CodeTransition(),
Factory.MetaCode("Code").Accepts(AcceptedCharacters.None),
Factory.Span(SpanKind.Code, new VBSymbol(5, 0, 5, String.Empty, VBSymbolType.Unknown))
.With(new StatementCodeGenerator())
.With(new AutoCompleteEditHandler(CSharpLanguageCharacteristics.Instance.TokenizeString) { AutoCompleteString = SyntaxConstants.VB.EndCodeKeyword })),
new RazorError(
String.Format(RazorResources.ParseError_BlockNotTerminated, "Code", "End Code"),
1, 0, 1));
}
[Fact]
public void FunctionsDirective_AutoComplete_At_StartOfFile()
{
ParseBlockTest("@Functions" + Environment.NewLine
+ "foo",
new FunctionsBlock(
Factory.CodeTransition("@").Accepts(AcceptedCharacters.None),
Factory.MetaCode("Functions").Accepts(AcceptedCharacters.None),
Factory.Code("\r\nfoo")
.AsFunctionsBody()
.With(new AutoCompleteEditHandler(CSharpLanguageCharacteristics.Instance.TokenizeString)
{
AutoCompleteString = SyntaxConstants.VB.EndFunctionsKeyword
})),
new RazorError(
String.Format(RazorResources.ParseError_BlockNotTerminated, "Functions", "End Functions"),
1, 0, 1));
}
[Fact]
public void HelperDirective_AutoComplete_At_StartOfFile()
{
ParseBlockTest("@Helper Strong(value As String)" + Environment.NewLine
+ "Foo",
new HelperBlock(new HelperCodeGenerator(new LocationTagged<string>("Strong(value As String)", 8, 0, 8), headerComplete: true),
Factory.CodeTransition(),
Factory.MetaCode("Helper ")
.Accepts(AcceptedCharacters.None),
Factory.Code("Strong(value As String)")
.Hidden()
.Accepts(AcceptedCharacters.None)
.With(new AutoCompleteEditHandler(CSharpLanguageCharacteristics.Instance.TokenizeString) { AutoCompleteString = SyntaxConstants.VB.EndHelperKeyword }),
new StatementBlock(
Factory.Code("\r\nFoo").AsStatement())),
new RazorError(
String.Format(RazorResources.ParseError_BlockNotTerminated, "Helper", "End Helper"),
1, 0, 1));
}
[Fact]
public void SectionDirective_AutoComplete_At_StartOfFile()
{
ParseBlockTest("@Section Header" + Environment.NewLine
+ "Foo",
new SectionBlock(new SectionCodeGenerator("Header"),
Factory.CodeTransition(),
Factory.MetaCode("Section Header")
.With(new AutoCompleteEditHandler(CSharpLanguageCharacteristics.Instance.TokenizeString) { AutoCompleteString = SyntaxConstants.VB.EndSectionKeyword }),
new MarkupBlock(
Factory.Markup("\r\nFoo")
.With(new MarkupCodeGenerator()))),
new RazorError(
String.Format(RazorResources.ParseError_BlockNotTerminated, "Section", "End Section"),
1, 0, 1));
}
[Fact]
public void VerbatimBlock_AutoComplete_At_StartOfFile()
{
ParseBlockTest("@Code" + Environment.NewLine
+ "Foo",
new StatementBlock(
Factory.CodeTransition(),
Factory.MetaCode("Code").Accepts(AcceptedCharacters.None),
Factory.Code("\r\nFoo")
.AsStatement()
.With(new AutoCompleteEditHandler(CSharpLanguageCharacteristics.Instance.TokenizeString) { AutoCompleteString = SyntaxConstants.VB.EndCodeKeyword })),
new RazorError(
String.Format(RazorResources.ParseError_BlockNotTerminated, "Code", "End Code"),
1, 0, 1));
}
}
}

View File

@ -0,0 +1,367 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Resources;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.AspNet.Razor.Text;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.Razor.Test.Parser.VB
{
public class VBBlockTest : VBHtmlCodeParserTestBase
{
[Fact]
public void ParseBlockMethodThrowsArgNullExceptionOnNullContext()
{
// Arrange
VBCodeParser parser = new VBCodeParser();
// Act and Assert
Assert.Throws<InvalidOperationException>(() => parser.ParseBlock(), RazorResources.Parser_Context_Not_Set);
}
[Fact]
public void ParseBlockAcceptsImplicitExpression()
{
ParseBlockTest("If True Then" + Environment.NewLine
+ " @foo" + Environment.NewLine
+ "End If",
new StatementBlock(
Factory.Code("If True Then\r\n ").AsStatement(),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("foo")
.AsImplicitExpression(VBCodeParser.DefaultKeywords, acceptTrailingDot: true)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
Factory.Code("\r\nEnd If")
.AsStatement()
.Accepts(AcceptedCharacters.None)));
}
[Fact]
public void ParseBlockAcceptsIfStatementWithinCodeBlockIfInDesignTimeMode()
{
ParseBlockTest("If True Then" + Environment.NewLine
+ " @If True Then" + Environment.NewLine
+ " End If" + Environment.NewLine
+ "End If",
new StatementBlock(
Factory.Code("If True Then\r\n ").AsStatement(),
new StatementBlock(
Factory.CodeTransition(),
Factory.Code("If True Then\r\n End If\r\n")
.AsStatement()
.Accepts(AcceptedCharacters.None)),
Factory.Code(@"End If")
.AsStatement()
.Accepts(AcceptedCharacters.None)));
}
[Fact]
public void ParseBlockSupportsSpacesInStrings()
{
ParseBlockTest("for each p in db.Query(\"SELECT * FROM PRODUCTS\")" + Environment.NewLine
+ " @<p>@p.Name</p>" + Environment.NewLine
+ "next",
new StatementBlock(
Factory.Code("for each p in db.Query(\"SELECT * FROM PRODUCTS\")\r\n")
.AsStatement(),
new MarkupBlock(
Factory.Markup(" "),
Factory.MarkupTransition(),
Factory.Markup("<p>"),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("p.Name")
.AsImplicitExpression(VBCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
Factory.Markup("</p>\r\n").Accepts(AcceptedCharacters.None)),
Factory.Code("next")
.AsStatement()
.Accepts(AcceptedCharacters.WhiteSpace | AcceptedCharacters.NonWhiteSpace)));
}
[Fact]
public void ParseBlockSupportsSimpleCodeBlock()
{
ParseBlockTest("Code" + Environment.NewLine
+ " If foo IsNot Nothing" + Environment.NewLine
+ " Bar(foo)" + Environment.NewLine
+ " End If" + Environment.NewLine
+ "End Code",
new StatementBlock(
Factory.MetaCode("Code").Accepts(AcceptedCharacters.None),
Factory.Code("\r\n If foo IsNot Nothing\r\n Bar(foo)\r\n End If\r\n")
.AsStatement(),
Factory.MetaCode("End Code").Accepts(AcceptedCharacters.None)));
}
[Fact]
public void ParseBlockRejectsNewlineBetweenEndAndCodeIfNotPrefixedWithUnderscore()
{
ParseBlockTest("Code" + Environment.NewLine
+ " If foo IsNot Nothing" + Environment.NewLine
+ " Bar(foo)" + Environment.NewLine
+ " End If" + Environment.NewLine
+ "End" + Environment.NewLine
+ "Code",
new StatementBlock(
Factory.MetaCode("Code").Accepts(AcceptedCharacters.None),
Factory.Code("\r\n If foo IsNot Nothing\r\n Bar(foo)\r\n End If\r\nEnd\r\nCode")
.AsStatement()),
new RazorError(
String.Format(RazorResources.ParseError_BlockNotTerminated, "Code", "End Code"),
SourceLocation.Zero));
}
[Fact]
public void ParseBlockAcceptsNewlineBetweenEndAndCodeIfPrefixedWithUnderscore()
{
ParseBlockTest("Code" + Environment.NewLine
+ " If foo IsNot Nothing" + Environment.NewLine
+ " Bar(foo)" + Environment.NewLine
+ " End If" + Environment.NewLine
+ "End _" + Environment.NewLine
+ "_" + Environment.NewLine
+ " _" + Environment.NewLine
+ "Code",
new StatementBlock(
Factory.MetaCode("Code").Accepts(AcceptedCharacters.None),
Factory.Code("\r\n If foo IsNot Nothing\r\n Bar(foo)\r\n End If\r\n")
.AsStatement(),
Factory.MetaCode("End _\r\n_\r\n _\r\nCode").Accepts(AcceptedCharacters.None)));
}
[Fact]
public void ParseBlockSupportsSimpleFunctionsBlock()
{
ParseBlockTest("Functions" + Environment.NewLine
+ " Public Sub Foo()" + Environment.NewLine
+ " Bar()" + Environment.NewLine
+ " End Sub" + Environment.NewLine
+ Environment.NewLine
+ " Private Function Bar() As Object" + Environment.NewLine
+ " Return Nothing" + Environment.NewLine
+ " End Function" + Environment.NewLine
+ "End Functions",
new FunctionsBlock(
Factory.MetaCode("Functions").Accepts(AcceptedCharacters.None),
Factory.Code("\r\n Public Sub Foo()\r\n Bar()\r\n End Sub\r\n\r\n Private Function Bar() As Object\r\n Return Nothing\r\n End Function\r\n")
.AsFunctionsBody(),
Factory.MetaCode("End Functions").Accepts(AcceptedCharacters.None)));
}
[Fact]
public void ParseBlockRejectsNewlineBetweenEndAndFunctionsIfNotPrefixedWithUnderscore()
{
ParseBlockTest("Functions" + Environment.NewLine
+ " If foo IsNot Nothing" + Environment.NewLine
+ " Bar(foo)" + Environment.NewLine
+ " End If" + Environment.NewLine
+ "End" + Environment.NewLine
+ "Functions",
new FunctionsBlock(
Factory.MetaCode("Functions").Accepts(AcceptedCharacters.None),
Factory.Code("\r\n If foo IsNot Nothing\r\n Bar(foo)\r\n End If\r\nEnd\r\nFunctions")
.AsFunctionsBody()),
new RazorError(
String.Format(RazorResources.ParseError_BlockNotTerminated, "Functions", "End Functions"),
SourceLocation.Zero));
}
[Fact]
public void ParseBlockAcceptsNewlineBetweenEndAndFunctionsIfPrefixedWithUnderscore()
{
ParseBlockTest("Functions" + Environment.NewLine
+ " If foo IsNot Nothing" + Environment.NewLine
+ " Bar(foo)" + Environment.NewLine
+ " End If" + Environment.NewLine
+ "End _" + Environment.NewLine
+ "_" + Environment.NewLine
+ " _" + Environment.NewLine
+ "Functions",
new FunctionsBlock(
Factory.MetaCode("Functions").Accepts(AcceptedCharacters.None),
Factory.Code("\r\n If foo IsNot Nothing\r\n Bar(foo)\r\n End If\r\n")
.AsFunctionsBody(),
Factory.MetaCode("End _\r\n_\r\n _\r\nFunctions").Accepts(AcceptedCharacters.None)));
}
[Fact]
public void ParseBlockCorrectlyHandlesExtraEndsInEndCode()
{
ParseBlockTest("Code" + Environment.NewLine
+ " Bar End" + Environment.NewLine
+ "End Code",
new StatementBlock(
Factory.MetaCode("Code").Accepts(AcceptedCharacters.None),
Factory.Code("\r\n Bar End\r\n").AsStatement(),
Factory.MetaCode("End Code").Accepts(AcceptedCharacters.None)));
}
[Fact]
public void ParseBlockCorrectlyHandlesExtraEndsInEndFunctions()
{
ParseBlockTest("Functions" + Environment.NewLine
+ " Bar End" + Environment.NewLine
+ "End Functions",
new FunctionsBlock(
Factory.MetaCode("Functions").Accepts(AcceptedCharacters.None),
Factory.Code("\r\n Bar End\r\n").AsFunctionsBody().AutoCompleteWith(null, atEndOfSpan: false),
Factory.MetaCode("End Functions").Accepts(AcceptedCharacters.None)));
}
[Theory]
[InlineData("If", "End", "If")]
[InlineData("Try", "End", "Try")]
[InlineData("While", "End", "While")]
[InlineData("Using", "End", "Using")]
[InlineData("With", "End", "With")]
public void KeywordAllowsNewlinesIfPrefixedByUnderscore(string startKeyword, string endKeyword1, string endKeyword2)
{
string code = startKeyword + Environment.NewLine
+ " ' In the block" + Environment.NewLine
+ endKeyword1 + " _" + Environment.NewLine
+ "_" + Environment.NewLine
+ "_" + Environment.NewLine
+ "_" + Environment.NewLine
+ "_" + Environment.NewLine
+ "_" + Environment.NewLine
+ " " + endKeyword2 + Environment.NewLine;
ParseBlockTest(code + "foo bar baz",
new StatementBlock(
Factory.Code(code)
.AsStatement()
.Accepts(AcceptedCharacters.None)));
}
[Theory]
[InlineData("While", "EndWhile", "End While")]
[InlineData("If", "EndIf", "End If")]
[InlineData("Select", "EndSelect", "End Select")]
[InlineData("Try", "EndTry", "End Try")]
[InlineData("With", "EndWith", "End With")]
[InlineData("Using", "EndUsing", "End Using")]
public void EndTerminatedKeywordRequiresSpaceBetweenEndAndKeyword(string startKeyword, string wrongEndKeyword, string endKeyword)
{
string code = startKeyword + Environment.NewLine
+ " ' This should not end the code" + Environment.NewLine
+ " " + wrongEndKeyword + Environment.NewLine
+ " ' But this should" + Environment.NewLine
+ endKeyword;
ParseBlockTest(code,
new StatementBlock(
Factory.Code(code)
.AsStatement()
.Accepts(AcceptedCharacters.None)));
}
[Theory]
[InlineData("While", "End While", false)]
[InlineData("Do", "Loop", true)]
[InlineData("If", "End If", false)]
[InlineData("Select", "End Select", false)]
[InlineData("For", "Next", true)]
[InlineData("Try", "End Try", false)]
[InlineData("With", "End With", false)]
[InlineData("Using", "End Using", false)]
public void EndSequenceInString(string keyword, string endSequence, bool acceptToEndOfLine)
{
string code = keyword + Environment.NewLine
+ " \"" + endSequence + "\"" + Environment.NewLine
+ endSequence + (acceptToEndOfLine ? " foo bar baz" : "") + Environment.NewLine;
ParseBlockTest(code + "biz boz",
new StatementBlock(
Factory.Code(code).AsStatement().Accepts(GetAcceptedCharacters(acceptToEndOfLine))));
}
[Theory]
[InlineData("While", "End While", false)]
[InlineData("Do", "Loop", true)]
[InlineData("If", "End If", false)]
[InlineData("Select", "End Select", false)]
[InlineData("For", "Next", true)]
[InlineData("Try", "End Try", false)]
[InlineData("With", "End With", false)]
[InlineData("Using", "End Using", false)]
private void CommentedEndSequence(string keyword, string endSequence, bool acceptToEndOfLine)
{
string code = keyword + Environment.NewLine
+ " '" + endSequence + Environment.NewLine
+ endSequence + (acceptToEndOfLine ? @" foo bar baz" : "") + Environment.NewLine;
ParseBlockTest(code + "biz boz",
new StatementBlock(
Factory.Code(code).AsStatement().Accepts(GetAcceptedCharacters(acceptToEndOfLine))));
}
[Theory]
[InlineData("While", "End While", false)]
[InlineData("Do", "Loop", true)]
[InlineData("If", "End If", false)]
[InlineData("Select", "End Select", false)]
[InlineData("For", "Next", true)]
[InlineData("Try", "End Try", false)]
[InlineData("With", "End With", false)]
[InlineData("SyncLock", "End SyncLock", false)]
[InlineData("Using", "End Using", false)]
private void NestedKeywordBlock(string keyword, string endSequence, bool acceptToEndOfLine)
{
string code = keyword + Environment.NewLine
+ " " + keyword + Environment.NewLine
+ " Bar(foo)" + Environment.NewLine
+ " " + endSequence + Environment.NewLine
+ endSequence + (acceptToEndOfLine ? " foo bar baz" : "") + Environment.NewLine;
ParseBlockTest(code + "biz boz",
new StatementBlock(
Factory.Code(code).AsStatement().Accepts(GetAcceptedCharacters(acceptToEndOfLine))));
}
[Theory]
[InlineData("While True", "End While", false)]
[InlineData("Do", "Loop", true)]
[InlineData("If foo IsNot Nothing", "End If", false)]
[InlineData("Select Case foo", "End Select", false)]
[InlineData("For Each p in Products", "Next", true)]
[InlineData("Try", "End Try", false)]
[InlineData("With", "End With", false)]
[InlineData("SyncLock", "End SyncLock", false)]
[InlineData("Using", "End Using", false)]
private void SimpleKeywordBlock(string keyword, string endSequence, bool acceptToEndOfLine)
{
string code = keyword + Environment.NewLine
+ " Bar(foo)" + Environment.NewLine
+ endSequence + (acceptToEndOfLine ? " foo bar baz" : "") + Environment.NewLine;
ParseBlockTest(code + "biz boz",
new StatementBlock(
Factory.Code(code).AsStatement().Accepts(GetAcceptedCharacters(acceptToEndOfLine))));
}
[Theory]
[InlineData("While True", "Exit While", "End While", false)]
[InlineData("Do", "Exit Do", "Loop", true)]
[InlineData("For Each p in Products", "Exit For", "Next", true)]
[InlineData("While True", "Continue While", "End While", false)]
[InlineData("Do", "Continue Do", "Loop", true)]
[InlineData("For Each p in Products", "Continue For", "Next", true)]
private void KeywordWithExitOrContinue(string startKeyword, string exitKeyword, string endKeyword, bool acceptToEndOfLine)
{
string code = startKeyword + Environment.NewLine
+ " ' This is before the exit" + Environment.NewLine
+ " " + exitKeyword + Environment.NewLine
+ " ' This is after the exit" + Environment.NewLine
+ endKeyword + Environment.NewLine;
ParseBlockTest(code + "foo bar baz",
new StatementBlock(
Factory.Code(code).AsStatement().Accepts(GetAcceptedCharacters(acceptToEndOfLine))));
}
private AcceptedCharacters GetAcceptedCharacters(bool acceptToEndOfLine)
{
return acceptToEndOfLine ?
AcceptedCharacters.WhiteSpace | AcceptedCharacters.NonWhiteSpace :
AcceptedCharacters.None;
}
}
}

View File

@ -0,0 +1,59 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.Razor.Test.Parser.VB
{
// VB Continue Statement: http://msdn.microsoft.com/en-us/library/801hyx6f.aspx
public class VBContinueStatementTest : VBHtmlCodeParserTestBase
{
[Fact]
public void VB_Do_Statement_With_Continue()
{
ParseBlockTest("@Do While True" + Environment.NewLine
+ " Continue Do" + Environment.NewLine
+ "Loop" + Environment.NewLine
+ "' Not in the block!",
new StatementBlock(
Factory.CodeTransition(SyntaxConstants.TransitionString)
.Accepts(AcceptedCharacters.None),
Factory.Code("Do While True\r\n Continue Do\r\nLoop\r\n")
.AsStatement()
.Accepts(AcceptedCharacters.AnyExceptNewline)));
}
[Fact]
public void VB_For_Statement_With_Continue()
{
ParseBlockTest("@For i = 1 To 12" + Environment.NewLine
+ " Continue For" + Environment.NewLine
+ "Next i" + Environment.NewLine
+ "' Not in the block!",
new StatementBlock(
Factory.CodeTransition(SyntaxConstants.TransitionString)
.Accepts(AcceptedCharacters.None),
Factory.Code("For i = 1 To 12\r\n Continue For\r\nNext i\r\n")
.AsStatement()
.Accepts(AcceptedCharacters.AnyExceptNewline)));
}
[Fact]
public void VB_While_Statement_With_Continue()
{
ParseBlockTest("@While True" + Environment.NewLine
+ " Continue While" + Environment.NewLine
+ "End While" + Environment.NewLine
+ "' Not in the block!",
new StatementBlock(
Factory.CodeTransition(SyntaxConstants.TransitionString)
.Accepts(AcceptedCharacters.None),
Factory.Code("While True\r\n Continue While\r\nEnd While\r\n")
.AsStatement()
.Accepts(AcceptedCharacters.None)));
}
}
}

View File

@ -0,0 +1,128 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.Razor.Generator;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.AspNet.Razor.Text;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.Razor.Test.Parser.VB
{
public class VBDirectiveTest : VBHtmlCodeParserTestBase
{
[Fact]
public void VB_Code_Directive()
{
ParseBlockTest("@Code" + Environment.NewLine
+ " foo()" + Environment.NewLine
+ "End Code" + Environment.NewLine
+ "' Not part of the block",
new StatementBlock(
Factory.CodeTransition(SyntaxConstants.TransitionString)
.Accepts(AcceptedCharacters.None),
Factory.MetaCode("Code")
.Accepts(AcceptedCharacters.None),
Factory.Code("\r\n foo()\r\n")
.AsStatement()
.With(new AutoCompleteEditHandler(VBLanguageCharacteristics.Instance.TokenizeString)),
Factory.MetaCode("End Code")
.Accepts(AcceptedCharacters.None)));
}
[Fact]
public void VB_Functions_Directive()
{
ParseBlockTest("@Functions" + Environment.NewLine
+ " Public Function Foo() As String" + Environment.NewLine
+ " Return \"Foo\"" + Environment.NewLine
+ " End Function" + Environment.NewLine
+ Environment.NewLine
+ " Public Sub Bar()" + Environment.NewLine
+ " End Sub" + Environment.NewLine
+ "End Functions" + Environment.NewLine
+ "' Not part of the block",
new FunctionsBlock(
Factory.CodeTransition(SyntaxConstants.TransitionString)
.Accepts(AcceptedCharacters.None),
Factory.MetaCode("Functions")
.Accepts(AcceptedCharacters.None),
Factory.Code("\r\n Public Function Foo() As String\r\n Return \"Foo\"\r\n End Function\r\n\r\n Public Sub Bar()\r\n End Sub\r\n")
.AsFunctionsBody(),
Factory.MetaCode("End Functions")
.Accepts(AcceptedCharacters.None)));
}
[Fact]
public void VB_Section_Directive()
{
ParseBlockTest("@Section Header" + Environment.NewLine
+ " <p>Foo</p>" + Environment.NewLine
+ "End Section",
new SectionBlock(new SectionCodeGenerator("Header"),
Factory.CodeTransition(SyntaxConstants.TransitionString),
Factory.MetaCode("Section Header"),
new MarkupBlock(
Factory.Markup("\r\n <p>Foo</p>\r\n")),
Factory.MetaCode("End Section")
.Accepts(AcceptedCharacters.None)));
}
[Fact]
public void SessionStateDirectiveWorks()
{
ParseBlockTest("@SessionState InProc" + Environment.NewLine,
new DirectiveBlock(
Factory.CodeTransition(),
Factory.MetaCode("SessionState ")
.Accepts(AcceptedCharacters.None),
Factory.MetaCode("InProc\r\n")
.Accepts(AcceptedCharacters.None)
.With(new RazorDirectiveAttributeCodeGenerator("SessionState", "InProc"))
)
);
}
[Fact]
public void SessionStateDirectiveIsCaseInsensitive()
{
ParseBlockTest("@sessionstate disabled" + Environment.NewLine,
new DirectiveBlock(
Factory.CodeTransition(),
Factory.MetaCode("sessionstate ")
.Accepts(AcceptedCharacters.None),
Factory.MetaCode("disabled\r\n")
.Accepts(AcceptedCharacters.None)
.With(new RazorDirectiveAttributeCodeGenerator("SessionState", "disabled"))
)
);
}
[Fact]
public void VB_Helper_Directive()
{
ParseBlockTest("@Helper Strong(s as String)" + Environment.NewLine
+ " s = s.ToUpperCase()" + Environment.NewLine
+ " @<strong>s</strong>" + Environment.NewLine
+ "End Helper",
new HelperBlock(new HelperCodeGenerator(new LocationTagged<string>("Strong(s as String)", 8, 0, 8), headerComplete: true),
Factory.CodeTransition(SyntaxConstants.TransitionString),
Factory.MetaCode("Helper ")
.Accepts(AcceptedCharacters.None),
Factory.Code("Strong(s as String)").Hidden(),
new StatementBlock(
Factory.Code("\r\n s = s.ToUpperCase()\r\n")
.AsStatement(),
new MarkupBlock(
Factory.Markup(" "),
Factory.MarkupTransition(SyntaxConstants.TransitionString),
Factory.Markup("<strong>s</strong>\r\n")
.Accepts(AcceptedCharacters.None)),
Factory.EmptyVB()
.AsStatement(),
Factory.MetaCode("End Helper")
.Accepts(AcceptedCharacters.None))));
}
}
}

View File

@ -0,0 +1,174 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.Razor.Editor;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Resources;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.AspNet.Razor.Text;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.Razor.Test.Parser.VB
{
public class VBErrorTest : VBHtmlCodeParserTestBase
{
[Fact]
public void ParserOutputsErrorAndRecoversToEndOfLineIfExplicitExpressionUnterminated()
{
ParseBlockTest(@"(foo
bar",
new ExpressionBlock(
Factory.MetaCode("(").Accepts(AcceptedCharacters.None),
Factory.Code("foo").AsExpression()),
new RazorError(
String.Format(
RazorResources.ParseError_Expected_EndOfBlock_Before_EOF,
RazorResources.BlockName_ExplicitExpression,
")", "("),
SourceLocation.Zero));
}
[Fact]
public void ParserOutputsZeroLengthCodeSpanIfEofReachedAfterStartOfExplicitExpression()
{
ParseBlockTest("(",
new ExpressionBlock(
Factory.MetaCode("(").Accepts(AcceptedCharacters.None),
Factory.EmptyVB().AsExpression()),
new RazorError(
String.Format(RazorResources.ParseError_Expected_EndOfBlock_Before_EOF, "explicit expression", ")", "("),
SourceLocation.Zero));
}
[Fact]
public void ParserOutputsZeroLengthCodeSpanIfEofReachedAfterAtSign()
{
ParseBlockTest(String.Empty,
new ExpressionBlock(
Factory.EmptyVB().AsImplicitExpression(KeywordSet).Accepts(AcceptedCharacters.NonWhiteSpace)),
new RazorError(
RazorResources.ParseError_Unexpected_EndOfFile_At_Start_Of_CodeBlock,
SourceLocation.Zero));
}
[Fact]
public void ParserOutputsZeroLengthCodeSpanIfOnlyWhitespaceFoundAfterAtSign()
{
ParseBlockTest(" ",
new ExpressionBlock(
Factory.EmptyVB().AsImplicitExpression(KeywordSet).Accepts(AcceptedCharacters.NonWhiteSpace)),
new RazorError(
RazorResources.ParseError_Unexpected_WhiteSpace_At_Start_Of_CodeBlock_VB,
SourceLocation.Zero));
}
[Fact]
public void ParserOutputsZeroLengthCodeSpanIfInvalidCharacterFoundAfterAtSign()
{
ParseBlockTest("!!!",
new ExpressionBlock(
Factory.EmptyVB().AsImplicitExpression(KeywordSet).Accepts(AcceptedCharacters.NonWhiteSpace)),
new RazorError(
String.Format(RazorResources.ParseError_Unexpected_Character_At_Start_Of_CodeBlock_VB, "!"),
SourceLocation.Zero));
}
[Theory]
[InlineData("Code", "End Code", true, true)]
[InlineData("Do", "Loop", false, false)]
[InlineData("While", "End While", false, false)]
[InlineData("If", "End If", false, false)]
[InlineData("Select Case", "End Select", false, false)]
[InlineData("For", "Next", false, false)]
[InlineData("Try", "End Try", false, false)]
[InlineData("With", "End With", false, false)]
[InlineData("Using", "End Using", false, false)]
public void EofBlock(string keyword, string expectedTerminator, bool autoComplete, bool keywordIsMetaCode)
{
EofBlockCore(keyword, expectedTerminator, autoComplete, BlockType.Statement, keywordIsMetaCode, c => c.AsStatement());
}
[Fact]
public void EofFunctionsBlock()
{
EofBlockCore("Functions", "End Functions", true, BlockType.Functions, true, c => c.AsFunctionsBody());
}
private void EofBlockCore(string keyword, string expectedTerminator, bool autoComplete, BlockType blockType, bool keywordIsMetaCode, Func<UnclassifiedCodeSpanConstructor, SpanConstructor> classifier)
{
BlockBuilder expected = new BlockBuilder();
expected.Type = blockType;
if (keywordIsMetaCode)
{
expected.Children.Add(Factory.MetaCode(keyword).Accepts(AcceptedCharacters.None));
expected.Children.Add(
classifier(Factory.EmptyVB())
.With((SpanEditHandler)(
autoComplete ?
new AutoCompleteEditHandler(CSharpLanguageCharacteristics.Instance.TokenizeString) { AutoCompleteString = expectedTerminator } :
SpanEditHandler.CreateDefault())));
}
else
{
expected.Children.Add(
classifier(Factory.Code(keyword))
.With((SpanEditHandler)(
autoComplete ?
new AutoCompleteEditHandler(CSharpLanguageCharacteristics.Instance.TokenizeString) { AutoCompleteString = expectedTerminator } :
SpanEditHandler.CreateDefault())));
}
ParseBlockTest(keyword,
expected.Build(),
new RazorError(
String.Format(RazorResources.ParseError_BlockNotTerminated, keyword, expectedTerminator),
SourceLocation.Zero));
}
[Theory]
[InlineData("Code", "End Code", true)]
[InlineData("Do", "Loop", false)]
[InlineData("While", "End While", false)]
[InlineData("If", "End If", false)]
[InlineData("Select Case", "End Select", false)]
[InlineData("For", "Next", false)]
[InlineData("Try", "End Try", false)]
[InlineData("With", "End With", false)]
[InlineData("Using", "End Using", false)]
public void UnterminatedBlock(string keyword, string expectedTerminator, bool keywordIsMetaCode)
{
UnterminatedBlockCore(keyword, expectedTerminator, BlockType.Statement, keywordIsMetaCode, c => c.AsStatement());
}
[Fact]
public void UnterminatedFunctionsBlock()
{
UnterminatedBlockCore("Functions", "End Functions", BlockType.Functions, true, c => c.AsFunctionsBody());
}
private void UnterminatedBlockCore(string keyword, string expectedTerminator, BlockType blockType, bool keywordIsMetaCode, Func<UnclassifiedCodeSpanConstructor, SpanConstructor> classifier)
{
const string blockBody = @"
' This block is not correctly terminated!";
BlockBuilder expected = new BlockBuilder();
expected.Type = blockType;
if (keywordIsMetaCode)
{
expected.Children.Add(Factory.MetaCode(keyword).Accepts(AcceptedCharacters.None));
expected.Children.Add(classifier(Factory.Code(blockBody)));
}
else
{
expected.Children.Add(classifier(Factory.Code(keyword + blockBody)));
}
ParseBlockTest(keyword + blockBody,
expected.Build(),
new RazorError(
String.Format(RazorResources.ParseError_BlockNotTerminated, keyword, expectedTerminator),
SourceLocation.Zero));
}
}
}

View File

@ -0,0 +1,97 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.Razor.Test.Parser.VB
{
// VB Exit Statement: http://msdn.microsoft.com/en-us/library/t2at9t47.aspx
public class VBExitStatementTest : VBHtmlCodeParserTestBase
{
[Fact]
public void VB_Do_Statement_With_Exit()
{
ParseBlockTest("@Do While True" + Environment.NewLine
+ " Exit Do" + Environment.NewLine
+ "Loop" + Environment.NewLine
+ "' Not in the block!",
new StatementBlock(
Factory.CodeTransition(SyntaxConstants.TransitionString)
.Accepts(AcceptedCharacters.None),
Factory.Code("Do While True\r\n Exit Do\r\nLoop\r\n")
.AsStatement()
.Accepts(AcceptedCharacters.AnyExceptNewline)));
}
[Fact]
public void VB_For_Statement_With_Exit()
{
ParseBlockTest("@For i = 1 To 12" + Environment.NewLine
+ " Exit For" + Environment.NewLine
+ "Next i" + Environment.NewLine
+ "' Not in the block!",
new StatementBlock(
Factory.CodeTransition(SyntaxConstants.TransitionString)
.Accepts(AcceptedCharacters.None),
Factory.Code("For i = 1 To 12\r\n Exit For\r\nNext i\r\n")
.AsStatement()
.Accepts(AcceptedCharacters.AnyExceptNewline)));
}
[Fact]
public void VB_Select_Statement_With_Exit()
{
ParseBlockTest("@Select Case Foo" + Environment.NewLine
+ " Case 1" + Environment.NewLine
+ " Exit Select" + Environment.NewLine
+ " Case 2" + Environment.NewLine
+ " Exit Select" + Environment.NewLine
+ "End Select" + Environment.NewLine
+ "' Not in the block!",
new StatementBlock(
Factory.CodeTransition(SyntaxConstants.TransitionString)
.Accepts(AcceptedCharacters.None),
Factory.Code("Select Case Foo\r\n Case 1\r\n Exit Select\r\n Case 2\r\n Exit Select\r\nEnd Select\r\n")
.AsStatement()
.Accepts(AcceptedCharacters.None)));
}
[Fact]
public void VB_Try_Statement_With_Exit()
{
ParseBlockTest("@Try" + Environment.NewLine
+ " Foo()" + Environment.NewLine
+ " Exit Try" + Environment.NewLine
+ "Catch Bar" + Environment.NewLine
+ " Throw Bar" + Environment.NewLine
+ "Finally" + Environment.NewLine
+ " Baz()" + Environment.NewLine
+ "End Try" + Environment.NewLine
+ "' Not in the block!",
new StatementBlock(
Factory.CodeTransition(SyntaxConstants.TransitionString)
.Accepts(AcceptedCharacters.None),
Factory.Code("Try\r\n Foo()\r\n Exit Try\r\nCatch Bar\r\n Throw Bar\r\nFinally\r\n Baz()\r\nEnd Try\r\n")
.AsStatement()
.Accepts(AcceptedCharacters.None)));
}
[Fact]
public void VB_While_Statement_With_Exit()
{
ParseBlockTest("@While True" + Environment.NewLine
+ " Exit While" + Environment.NewLine
+ "End While" + Environment.NewLine
+ "' Not in the block!",
new StatementBlock(
Factory.CodeTransition(SyntaxConstants.TransitionString)
.Accepts(AcceptedCharacters.None),
Factory.Code("While True\r\n Exit While\r\nEnd While\r\n")
.AsStatement()
.Accepts(AcceptedCharacters.None)));
}
}
}

View File

@ -0,0 +1,22 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.Razor.Test.Parser.VB
{
public class VBExplicitExpressionTest : VBHtmlCodeParserTestBase
{
[Fact]
public void VB_Simple_ExplicitExpression()
{
ParseBlockTest("@(foo)",
new ExpressionBlock(
Factory.CodeTransition(),
Factory.MetaCode("(").Accepts(AcceptedCharacters.None),
Factory.Code("foo").AsExpression(),
Factory.MetaCode(")").Accepts(AcceptedCharacters.None)));
}
}
}

View File

@ -0,0 +1,111 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Resources;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.AspNet.Razor.Text;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.Razor.Test.Parser.VB
{
public class VBExpressionTest : VBHtmlCodeParserTestBase
{
[Fact]
public void ParseBlockCorrectlyHandlesCodeBlockInBodyOfExplicitExpressionDueToUnclosedExpression()
{
ParseBlockTest(@"(
@Code
Dim foo = bar
End Code",
new ExpressionBlock(
Factory.MetaCode("(").Accepts(AcceptedCharacters.None),
Factory.EmptyVB().AsExpression()),
new RazorError(
String.Format(
RazorResources.ParseError_Expected_EndOfBlock_Before_EOF,
RazorResources.BlockName_ExplicitExpression,
")", "("),
SourceLocation.Zero));
}
[Fact]
public void ParseBlockAcceptsNonEnglishCharactersThatAreValidIdentifiers()
{
ImplicitExpressionTest("हळूँजद॔.", "हळूँजद॔");
}
[Fact]
public void ParseBlockDoesNotTreatXmlAxisPropertyAsTransitionToMarkup()
{
SingleSpanBlockTest(
@"If foo Is Nothing Then
Dim bar As XElement
Dim foo = bar.<foo>
End If",
BlockType.Statement,
SpanKind.Code,
acceptedCharacters: AcceptedCharacters.None);
}
[Fact]
public void ParseBlockDoesNotTreatXmlAttributePropertyAsTransitionToMarkup()
{
SingleSpanBlockTest(
@"If foo Is Nothing Then
Dim bar As XElement
Dim foo = bar.@foo
End If",
BlockType.Statement,
SpanKind.Code,
acceptedCharacters: AcceptedCharacters.None);
}
[Fact]
public void ParseBlockSupportsSimpleImplicitExpression()
{
ImplicitExpressionTest("Foo");
}
[Fact]
public void ParseBlockSupportsImplicitExpressionWithDots()
{
ImplicitExpressionTest("Foo.Bar.Baz");
}
[Fact]
public void ParseBlockSupportsImplicitExpressionWithParens()
{
ImplicitExpressionTest("Foo().Bar().Baz()");
}
[Fact]
public void ParseBlockSupportsImplicitExpressionWithStuffInParens()
{
ImplicitExpressionTest("Foo().Bar(sdfkhj sdfksdfjs \")\" sjdfkjsdf).Baz()");
}
[Fact]
public void ParseBlockSupportsImplicitExpressionWithCommentInParens()
{
ImplicitExpressionTest("Foo().Bar(sdfkhj sdfksdfjs \")\" '))))))))\r\nsjdfkjsdf).Baz()");
}
[Theory]
[InlineData("Foo")]
[InlineData("Foo(Of String).Bar(1, 2, 3).Biz")]
[InlineData("Foo(Of String).Bar(\")\").Biz")]
[InlineData("Foo(Of String).Bar(\"Foo\"\"Bar)\"\"Baz\").Biz")]
[InlineData("\"foo\r\nbar")]
[InlineData("Foo.Bar. _\r\nREM )\r\nBaz()\r\n")]
[InlineData("Foo.Bar. _\r\n' )\r\nBaz()\r\n")]
public void ValidExplicitExpressions(string body)
{
ParseBlockTest("(" + body + ")",
new ExpressionBlock(
Factory.MetaCode("(").Accepts(AcceptedCharacters.None),
Factory.Code(body).AsExpression(),
Factory.MetaCode(")").Accepts(AcceptedCharacters.None)));
}
}
}

View File

@ -0,0 +1,121 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Resources;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.Razor.Test.Parser.VB
{
public class VBExpressionsInCodeTest : VBHtmlCodeParserTestBase
{
[Fact]
public void InnerImplicitExpressionWithOnlySingleAtAcceptsSingleSpaceOrNewlineAtDesignTime()
{
ParseBlockTest("Code" + Environment.NewLine
+ " @" + Environment.NewLine
+ "End Code",
new StatementBlock(
Factory.MetaCode("Code").Accepts(AcceptedCharacters.None),
Factory.Code("\r\n ").AsStatement(),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.EmptyVB()
.AsImplicitExpression(VBCodeParser.DefaultKeywords, acceptTrailingDot: true)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
Factory.Code("\r\n").AsStatement(),
Factory.MetaCode("End Code").Accepts(AcceptedCharacters.None)),
designTimeParser: true,
expectedErrors: new[]
{
new RazorError(RazorResources.ParseError_Unexpected_WhiteSpace_At_Start_Of_CodeBlock_VB, 11, 1, 5)
});
}
[Fact]
public void InnerImplicitExpressionDoesNotAcceptDotAfterAt()
{
ParseBlockTest("Code" + Environment.NewLine
+ " @." + Environment.NewLine
+ "End Code",
new StatementBlock(
Factory.MetaCode("Code").Accepts(AcceptedCharacters.None),
Factory.Code("\r\n ").AsStatement(),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.EmptyVB()
.AsImplicitExpression(VBCodeParser.DefaultKeywords, acceptTrailingDot: true)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
Factory.Code(".\r\n").AsStatement(),
Factory.MetaCode("End Code").Accepts(AcceptedCharacters.None)),
designTimeParser: true,
expectedErrors: new[]
{
new RazorError(
String.Format(RazorResources.ParseError_Unexpected_Character_At_Start_Of_CodeBlock_VB, "."),
11, 1, 5)
});
}
[Theory]
[InlineData("Foo.Bar.", true)]
[InlineData("Foo", true)]
[InlineData("Foo.Bar.Baz", true)]
[InlineData("Foo().Bar().Baz()", true)]
[InlineData("Foo().Bar(sdfkhj sdfksdfjs \")\" sjdfkjsdf).Baz()", true)]
[InlineData("Foo().Bar(sdfkhj sdfksdfjs \")\" '))))))))\r\nsjdfkjsdf).Baz()", true)]
[InlineData("Foo", false)]
[InlineData("Foo(Of String).Bar(1, 2, 3).Biz", false)]
[InlineData("Foo(Of String).Bar(\")\").Biz", false)]
[InlineData("Foo(Of String).Bar(\"Foo\"\"Bar)\"\"Baz\").Biz", false)]
[InlineData("Foo.Bar. _\r\nREM )\r\nBaz()\r\n", false)]
[InlineData("Foo.Bar. _\r\n' )\r\nBaz()\r\n", false)]
public void ExpressionInCode(string expression, bool isImplicit)
{
ExpressionBlock expressionBlock;
if (isImplicit)
{
expressionBlock =
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code(expression)
.AsImplicitExpression(VBCodeParser.DefaultKeywords, acceptTrailingDot: true)
.Accepts(AcceptedCharacters.NonWhiteSpace));
}
else
{
expressionBlock =
new ExpressionBlock(
Factory.CodeTransition(),
Factory.MetaCode("(").Accepts(AcceptedCharacters.None),
Factory.Code(expression).AsExpression(),
Factory.MetaCode(")").Accepts(AcceptedCharacters.None));
}
string code;
if (isImplicit)
{
code = "If foo IsNot Nothing Then" + Environment.NewLine
+ " @" + expression + Environment.NewLine
+ "End If";
}
else
{
code = "If foo IsNot Nothing Then" + Environment.NewLine
+ " @(" + expression + ")" + Environment.NewLine
+ "End If";
}
ParseBlockTest(code,
new StatementBlock(
Factory.Code("If foo IsNot Nothing Then\r\n ")
.AsStatement(),
expressionBlock,
Factory.Code("\r\nEnd If")
.AsStatement()
.Accepts(AcceptedCharacters.None)));
}
}
}

View File

@ -0,0 +1,324 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.Razor.Generator;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Resources;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.AspNet.Razor.Text;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.Razor.Test.Parser.VB
{
public class VBHelperTest : VBHtmlMarkupParserTestBase
{
[Fact]
public void ParseHelperOutputsErrorButContinuesIfLParenFoundAfterHelperKeyword()
{
ParseDocumentTest("@Helper ()",
new MarkupBlock(
Factory.EmptyHtml(),
new HelperBlock(new HelperCodeGenerator(new LocationTagged<string>("()", 8, 0, 8), headerComplete: true),
Factory.CodeTransition(),
Factory.MetaCode("Helper ").Accepts(AcceptedCharacters.None),
Factory.Code("()").Hidden().AutoCompleteWith(SyntaxConstants.VB.EndHelperKeyword),
new StatementBlock())),
new RazorError(
String.Format(
RazorResources.ParseError_Unexpected_Character_At_Helper_Name_Start,
String.Format(RazorResources.ErrorComponent_Character, "(")),
8, 0, 8),
new RazorError(
String.Format(RazorResources.ParseError_BlockNotTerminated, "Helper", "End Helper"),
1, 0, 1));
}
[Fact]
public void ParseHelperStatementOutputsMarkerHelperHeaderSpanOnceKeywordComplete()
{
ParseDocumentTest("@Helper ",
new MarkupBlock(
Factory.EmptyHtml(),
new HelperBlock(new HelperCodeGenerator(new LocationTagged<string>(String.Empty, 8, 0, 8), headerComplete: false),
Factory.CodeTransition(),
Factory.MetaCode("Helper ").Accepts(AcceptedCharacters.None),
Factory.EmptyVB().Hidden())),
new RazorError(
String.Format(RazorResources.ParseError_Unexpected_Character_At_Helper_Name_Start, RazorResources.ErrorComponent_EndOfFile),
8, 0, 8));
}
[Fact]
public void ParseHelperStatementMarksHelperSpanAsCanGrowIfMissingTrailingSpace()
{
ParseDocumentTest("@Helper",
new MarkupBlock(
Factory.EmptyHtml(),
new HelperBlock(
Factory.CodeTransition(),
Factory.MetaCode("Helper"))),
new RazorError(
String.Format(RazorResources.ParseError_Unexpected_Character_At_Helper_Name_Start, RazorResources.ErrorComponent_EndOfFile),
7, 0, 7));
}
[Fact]
public void ParseHelperStatementTerminatesEarlyIfHeaderNotComplete()
{
ParseDocumentTest("@Helper" + Environment.NewLine
+ "@Helper",
new MarkupBlock(
Factory.EmptyHtml(),
new HelperBlock(
Factory.CodeTransition(),
Factory.MetaCode("Helper\r\n").Accepts(AcceptedCharacters.None),
Factory.EmptyVB().Hidden()),
new HelperBlock(
Factory.CodeTransition(),
Factory.MetaCode("Helper"))),
designTimeParser: true,
expectedErrors: new[]
{
new RazorError(
String.Format(
RazorResources.ParseError_Unexpected_Character_At_Helper_Name_Start,
String.Format(RazorResources.ErrorComponent_Character, "@")),
9, 1, 0),
new RazorError(
String.Format(
RazorResources.ParseError_Unexpected_Character_At_Helper_Name_Start,
RazorResources.ErrorComponent_EndOfFile),
16, 1, 7)
});
}
[Fact]
public void ParseHelperStatementTerminatesEarlyIfHeaderNotCompleteWithSpace()
{
ParseDocumentTest(@"@Helper @Helper",
new MarkupBlock(
Factory.EmptyHtml(),
new HelperBlock(new HelperCodeGenerator(new LocationTagged<string>(String.Empty, 8, 0, 8), headerComplete: false),
Factory.CodeTransition(),
Factory.MetaCode(@"Helper ").Accepts(AcceptedCharacters.None),
Factory.EmptyVB().Hidden()),
new HelperBlock(
Factory.CodeTransition(),
Factory.MetaCode("Helper").Accepts(AcceptedCharacters.Any))),
designTimeParser: true,
expectedErrors: new[]
{
new RazorError(
String.Format(
RazorResources.ParseError_Unexpected_Character_At_Helper_Name_Start,
String.Format(RazorResources.ErrorComponent_Character, "@")),
8, 0, 8),
new RazorError(
String.Format(
RazorResources.ParseError_Unexpected_Character_At_Helper_Name_Start,
RazorResources.ErrorComponent_EndOfFile),
15, 0, 15)
});
}
[Fact]
public void ParseHelperStatementAllowsDifferentlyCasedEndHelperKeyword()
{
ParseDocumentTest("@Helper Foo()" + Environment.NewLine
+ "end helper",
new MarkupBlock(
Factory.EmptyHtml(),
new HelperBlock(new HelperCodeGenerator(new LocationTagged<string>("Foo()", 8, 0, 8), headerComplete: true),
Factory.CodeTransition(),
Factory.MetaCode("Helper ").Accepts(AcceptedCharacters.None),
Factory.Code("Foo()").Hidden(),
new StatementBlock(
Factory.Code("\r\n").AsStatement(),
Factory.MetaCode("end helper").Accepts(AcceptedCharacters.None))),
Factory.EmptyHtml()));
}
[Fact]
public void ParseHelperStatementCapturesWhitespaceToEndOfLineIfHelperStatementMissingName()
{
ParseDocumentTest("@Helper " + Environment.NewLine
+ " ",
new MarkupBlock(
Factory.EmptyHtml(),
new HelperBlock(new HelperCodeGenerator(new LocationTagged<string>(" ", 8, 0, 8), headerComplete: false),
Factory.CodeTransition(),
Factory.MetaCode("Helper ").Accepts(AcceptedCharacters.None),
Factory.Code(" ").Hidden()),
Factory.Markup("\r\n ")),
new RazorError(
String.Format(
RazorResources.ParseError_Unexpected_Character_At_Helper_Name_Start,
RazorResources.ErrorComponent_Newline),
30, 0, 30));
}
[Fact]
public void ParseHelperStatementCapturesWhitespaceToEndOfLineIfHelperStatementMissingOpenParen()
{
ParseDocumentTest("@Helper Foo " + Environment.NewLine
+ " ",
new MarkupBlock(
Factory.EmptyHtml(),
new HelperBlock(new HelperCodeGenerator(new LocationTagged<string>("Foo ", 8, 0, 8), headerComplete: false),
Factory.CodeTransition(),
Factory.MetaCode("Helper ").Accepts(AcceptedCharacters.None),
Factory.Code("Foo ").Hidden()),
Factory.Markup("\r\n ")),
new RazorError(
String.Format(RazorResources.ParseError_MissingCharAfterHelperName, "("),
15, 0, 15));
}
[Fact]
public void ParseHelperStatementCapturesAllContentToEndOfFileIfHelperStatementMissingCloseParenInParameterList()
{
ParseDocumentTest("@Helper Foo(Foo Bar" + Environment.NewLine
+ "Biz" + Environment.NewLine
+ "Boz",
new MarkupBlock(
Factory.EmptyHtml(),
new HelperBlock(new HelperCodeGenerator(new LocationTagged<string>("Foo(Foo Bar\r\nBiz\r\nBoz", 8, 0, 8), headerComplete: false),
Factory.CodeTransition(),
Factory.MetaCode("Helper ").Accepts(AcceptedCharacters.None),
Factory.Code("Foo(Foo Bar\r\nBiz\r\nBoz").Hidden())),
new RazorError(RazorResources.ParseError_UnterminatedHelperParameterList, 11, 0, 11));
}
[Fact]
public void ParseHelperStatementCapturesWhitespaceToEndOfLineIfHelperStatementMissingOpenBraceAfterParameterList()
{
ParseDocumentTest("@Helper Foo(foo as String) " + Environment.NewLine,
new MarkupBlock(
Factory.EmptyHtml(),
new HelperBlock(new HelperCodeGenerator(new LocationTagged<string>("Foo(foo as String)", 8, 0, 8), headerComplete: true),
Factory.CodeTransition(),
Factory.MetaCode("Helper ").Accepts(AcceptedCharacters.None),
Factory.Code("Foo(foo as String)")
.Hidden()
.AutoCompleteWith(SyntaxConstants.VB.EndHelperKeyword),
new StatementBlock(
Factory.Code(" \r\n").AsStatement()))),
new RazorError(
String.Format(RazorResources.ParseError_BlockNotTerminated, "Helper", "End Helper"),
1, 0, 1));
}
[Fact]
public void ParseHelperStatementContinuesParsingHelperUntilEOF()
{
ParseDocumentTest("@Helper Foo(foo as String)" + Environment.NewLine
+ " @<p>Foo</p>",
new MarkupBlock(
Factory.EmptyHtml(),
new HelperBlock(new HelperCodeGenerator(new LocationTagged<string>("Foo(foo as String)", 8, 0, 8), headerComplete: true),
Factory.CodeTransition(),
Factory.MetaCode("Helper ").Accepts(AcceptedCharacters.None),
Factory.Code("Foo(foo as String)")
.Hidden()
.AutoCompleteWith(SyntaxConstants.VB.EndHelperKeyword),
new StatementBlock(
Factory.Code("\r\n").AsStatement(),
new MarkupBlock(
Factory.Markup(" "),
Factory.MarkupTransition(),
Factory.Markup("<p>Foo</p>").Accepts(AcceptedCharacters.None)),
Factory.EmptyVB().AsStatement()))),
new RazorError(
String.Format(RazorResources.ParseError_BlockNotTerminated, "Helper", "End Helper"),
1, 0, 1));
}
[Fact]
public void ParseHelperStatementCorrectlyParsesHelperWithEmbeddedCode()
{
ParseDocumentTest("@Helper Foo(foo as String, bar as String)" + Environment.NewLine
+ " @<p>@foo</p>" + Environment.NewLine
+ "End Helper",
new MarkupBlock(
Factory.EmptyHtml(),
new HelperBlock(new HelperCodeGenerator(new LocationTagged<string>("Foo(foo as String, bar as String)", 8, 0, 8), headerComplete: true),
Factory.CodeTransition(),
Factory.MetaCode("Helper ").Accepts(AcceptedCharacters.None),
Factory.Code("Foo(foo as String, bar as String)").Hidden(),
new StatementBlock(
Factory.Code("\r\n").AsStatement(),
new MarkupBlock(
Factory.Markup(" "),
Factory.MarkupTransition(),
Factory.Markup("<p>"),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("foo")
.AsImplicitExpression(VBCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
Factory.Markup("</p>\r\n").Accepts(AcceptedCharacters.None)),
Factory.EmptyVB().AsStatement(),
Factory.MetaCode("End Helper").Accepts(AcceptedCharacters.None))),
Factory.EmptyHtml()));
}
[Fact]
public void ParseHelperStatementGivesWhitespaceAfterCloseParenToMarkup()
{
ParseDocumentTest("@Helper Foo(string foo) " + Environment.NewLine
+ " ",
new MarkupBlock(
Factory.EmptyHtml(),
new HelperBlock(new HelperCodeGenerator(new LocationTagged<string>("Foo(string foo)", 8, 0, 8), headerComplete: true),
Factory.CodeTransition(),
Factory.MetaCode("Helper ").Accepts(AcceptedCharacters.None),
Factory.Code("Foo(string foo)")
.Hidden()
.AutoCompleteWith(SyntaxConstants.VB.EndHelperKeyword),
new StatementBlock(
Factory.Code(" \r\n ").AsStatement()))),
designTimeParser: true,
expectedErrors:
new RazorError(
String.Format(
RazorResources.ParseError_BlockNotTerminated,
"Helper", "End Helper"),
1, 0, 1));
}
[Fact]
public void ParseHelperAcceptsNestedHelpersButOutputsError()
{
ParseDocumentTest("@Helper Foo(string foo)" + Environment.NewLine
+ " @Helper Bar(string baz)" + Environment.NewLine
+ " End Helper" + Environment.NewLine
+ "End Helper",
new MarkupBlock(
Factory.EmptyHtml(),
new HelperBlock(new HelperCodeGenerator(new LocationTagged<string>("Foo(string foo)", 8, 0, 8), headerComplete: true),
Factory.CodeTransition(),
Factory.MetaCode("Helper ").Accepts(AcceptedCharacters.None),
Factory.Code("Foo(string foo)").Hidden(),
new StatementBlock(
Factory.Code("\r\n ").AsStatement(),
new HelperBlock(new HelperCodeGenerator(new LocationTagged<string>("Bar(string baz)", 37, 1, 12), headerComplete: true),
Factory.CodeTransition(),
Factory.MetaCode("Helper ").Accepts(AcceptedCharacters.None),
Factory.Code("Bar(string baz)").Hidden(),
new StatementBlock(
Factory.Code("\r\n ").AsStatement(),
Factory.MetaCode("End Helper").Accepts(AcceptedCharacters.None))),
Factory.Code("\r\n").AsStatement(),
Factory.MetaCode("End Helper").Accepts(AcceptedCharacters.None))),
Factory.EmptyHtml()),
designTimeParser: true,
expectedErrors: new[]
{
new RazorError(
RazorResources.ParseError_Helpers_Cannot_Be_Nested,
30, 1, 5)
});
}
}
}

View File

@ -0,0 +1,251 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.AspNet.Razor.Tokenizer.Symbols;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.Razor.Test.Parser.VB
{
public class VBHtmlDocumentTest : VBHtmlMarkupParserTestBase
{
[Fact]
public void BlockCommentInMarkupDocumentIsHandledCorrectly()
{
ParseDocumentTest(@"<ul>" + Environment.NewLine
+ @" @* This is a block comment </ul> *@ foo",
new MarkupBlock(
Factory.Markup("<ul>" + Environment.NewLine + " "),
new CommentBlock(
Factory.MarkupTransition(HtmlSymbolType.RazorCommentTransition),
Factory.MetaMarkup("*", HtmlSymbolType.RazorCommentStar).Accepts(AcceptedCharacters.None),
Factory.Comment(" This is a block comment </ul> ", HtmlSymbolType.RazorComment),
Factory.MetaMarkup("*", HtmlSymbolType.RazorCommentStar).Accepts(AcceptedCharacters.None),
Factory.MarkupTransition(HtmlSymbolType.RazorCommentTransition)),
Factory.Markup(" foo")));
}
[Fact]
public void BlockCommentInMarkupBlockIsHandledCorrectly()
{
ParseBlockTest(@"<ul>" + Environment.NewLine
+ @" @* This is a block comment </ul> *@ foo </ul>",
new MarkupBlock(
Factory.Markup("<ul>" + Environment.NewLine + " "),
new CommentBlock(
Factory.MarkupTransition(HtmlSymbolType.RazorCommentTransition),
Factory.MetaMarkup("*", HtmlSymbolType.RazorCommentStar).Accepts(AcceptedCharacters.None),
Factory.Comment(" This is a block comment </ul> ", HtmlSymbolType.RazorComment),
Factory.MetaMarkup("*", HtmlSymbolType.RazorCommentStar).Accepts(AcceptedCharacters.None),
Factory.MarkupTransition(HtmlSymbolType.RazorCommentTransition)),
Factory.Markup(" foo </ul>").Accepts(AcceptedCharacters.None)));
}
[Fact]
public void BlockCommentAtStatementStartInCodeBlockIsHandledCorrectly()
{
ParseDocumentTest(@"@If Request.IsAuthenticated Then" + Environment.NewLine
+ @" @* User is logged in! End If *@" + Environment.NewLine
+ @" Write(""Hello friend!"")" + Environment.NewLine
+ @"End If",
new MarkupBlock(
Factory.EmptyHtml(),
new StatementBlock(
Factory.CodeTransition(),
Factory.Code("If Request.IsAuthenticated Then" + Environment.NewLine + " ").AsStatement(),
new CommentBlock(
Factory.CodeTransition(VBSymbolType.RazorCommentTransition),
Factory.MetaCode("*", VBSymbolType.RazorCommentStar).Accepts(AcceptedCharacters.None),
Factory.Comment(" User is logged in! End If ", VBSymbolType.RazorComment),
Factory.MetaCode("*", VBSymbolType.RazorCommentStar).Accepts(AcceptedCharacters.None),
Factory.CodeTransition(VBSymbolType.RazorCommentTransition)),
Factory.Code("" + Environment.NewLine + " Write(\"Hello friend!\")" + Environment.NewLine + "End If")
.AsStatement()
.Accepts(AcceptedCharacters.None)),
Factory.EmptyHtml()));
}
[Fact]
public void BlockCommentInStatementInCodeBlockIsHandledCorrectly()
{
ParseDocumentTest(@"@If Request.IsAuthenticated Then" + Environment.NewLine
+ @" Dim foo = @* User is logged in! End If *@ bar" + Environment.NewLine
+ @" Write(""Hello friend!"")" + Environment.NewLine
+ @"End If",
new MarkupBlock(
Factory.EmptyHtml(),
new StatementBlock(
Factory.CodeTransition(),
Factory.Code("If Request.IsAuthenticated Then" + Environment.NewLine + " Dim foo = ").AsStatement(),
new CommentBlock(
Factory.CodeTransition(VBSymbolType.RazorCommentTransition),
Factory.MetaCode("*", VBSymbolType.RazorCommentStar).Accepts(AcceptedCharacters.None),
Factory.Comment(" User is logged in! End If ", VBSymbolType.RazorComment),
Factory.MetaCode("*", VBSymbolType.RazorCommentStar).Accepts(AcceptedCharacters.None),
Factory.CodeTransition(VBSymbolType.RazorCommentTransition)),
Factory.Code(" bar" + Environment.NewLine + " Write(\"Hello friend!\")" + Environment.NewLine + "End If")
.AsStatement()
.Accepts(AcceptedCharacters.None)),
Factory.EmptyHtml()));
}
[Fact]
public void BlockCommentInStringInCodeBlockIsIgnored()
{
ParseDocumentTest(@"@If Request.IsAuthenticated Then" + Environment.NewLine
+ @" Dim foo = ""@* User is logged in! End If *@ bar""" + Environment.NewLine
+ @" Write(""Hello friend!"")" + Environment.NewLine
+ @"End If",
new MarkupBlock(
Factory.EmptyHtml(),
new StatementBlock(
Factory.CodeTransition(),
Factory.Code("If Request.IsAuthenticated Then" + Environment.NewLine + " Dim foo = \"@* User is logged in! End If *@ bar\"" + Environment.NewLine + " Write(\"Hello friend!\")" + Environment.NewLine + "End If")
.AsStatement()
.Accepts(AcceptedCharacters.None)),
Factory.EmptyHtml()));
}
[Fact]
public void BlockCommentInTickCommentInCodeBlockIsIgnored()
{
ParseDocumentTest(@"@If Request.IsAuthenticated Then" + Environment.NewLine
+ @" Dim foo = '@* User is logged in! End If *@ bar" + Environment.NewLine
+ @" Write(""Hello friend!"")" + Environment.NewLine
+ @"End If",
new MarkupBlock(
Factory.EmptyHtml(),
new StatementBlock(
Factory.CodeTransition(),
Factory.Code("If Request.IsAuthenticated Then" + Environment.NewLine + " Dim foo = '@* User is logged in! End If *@ bar" + Environment.NewLine + " Write(\"Hello friend!\")" + Environment.NewLine + "End If")
.AsStatement()
.Accepts(AcceptedCharacters.None)),
Factory.EmptyHtml()));
}
[Fact]
public void BlockCommentInRemCommentInCodeBlockIsIgnored()
{
ParseDocumentTest(@"@If Request.IsAuthenticated Then" + Environment.NewLine
+ @" Dim foo = REM @* User is logged in! End If *@ bar" + Environment.NewLine
+ @" Write(""Hello friend!"")" + Environment.NewLine
+ @"End If",
new MarkupBlock(
Factory.EmptyHtml(),
new StatementBlock(
Factory.CodeTransition(),
Factory.Code("If Request.IsAuthenticated Then" + Environment.NewLine + " Dim foo = REM @* User is logged in! End If *@ bar" + Environment.NewLine + " Write(\"Hello friend!\")" + Environment.NewLine + "End If")
.AsStatement()
.Accepts(AcceptedCharacters.None)),
Factory.EmptyHtml()));
}
[Fact]
public void BlockCommentInImplicitExpressionIsHandledCorrectly()
{
ParseDocumentTest("@Html.Foo@*bar*@",
new MarkupBlock(
Factory.EmptyHtml(),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("Html.Foo")
.AsImplicitExpression(KeywordSet)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
Factory.EmptyHtml(),
new CommentBlock(
Factory.MarkupTransition(HtmlSymbolType.RazorCommentTransition),
Factory.MetaMarkup("*", HtmlSymbolType.RazorCommentStar).Accepts(AcceptedCharacters.None),
Factory.Comment("bar", HtmlSymbolType.RazorComment),
Factory.MetaMarkup("*", HtmlSymbolType.RazorCommentStar).Accepts(AcceptedCharacters.None),
Factory.MarkupTransition(HtmlSymbolType.RazorCommentTransition)),
Factory.EmptyHtml()));
}
[Fact]
public void BlockCommentAfterDotOfImplicitExpressionIsHandledCorrectly()
{
ParseDocumentTest("@Html.@*bar*@",
new MarkupBlock(
Factory.EmptyHtml(),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("Html")
.AsImplicitExpression(KeywordSet)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
Factory.Markup("."),
new CommentBlock(
Factory.MarkupTransition(HtmlSymbolType.RazorCommentTransition),
Factory.MetaMarkup("*", HtmlSymbolType.RazorCommentStar).Accepts(AcceptedCharacters.None),
Factory.Comment("bar", HtmlSymbolType.RazorComment),
Factory.MetaMarkup("*", HtmlSymbolType.RazorCommentStar).Accepts(AcceptedCharacters.None),
Factory.MarkupTransition(HtmlSymbolType.RazorCommentTransition)),
Factory.EmptyHtml()));
}
[Fact]
public void BlockCommentInParensOfImplicitExpressionIsHandledCorrectly()
{
ParseDocumentTest("@Html.Foo(@*bar*@ 4)",
new MarkupBlock(
Factory.EmptyHtml(),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("Html.Foo(")
.AsImplicitExpression(KeywordSet)
.Accepts(AcceptedCharacters.Any),
new CommentBlock(
Factory.CodeTransition(VBSymbolType.RazorCommentTransition),
Factory.MetaCode("*", VBSymbolType.RazorCommentStar).Accepts(AcceptedCharacters.None),
Factory.Comment("bar", VBSymbolType.RazorComment),
Factory.MetaCode("*", VBSymbolType.RazorCommentStar).Accepts(AcceptedCharacters.None),
Factory.CodeTransition(VBSymbolType.RazorCommentTransition)),
Factory.Code(" 4)")
.AsImplicitExpression(KeywordSet)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
Factory.EmptyHtml()));
}
[Fact]
public void BlockCommentInConditionIsHandledCorrectly()
{
ParseDocumentTest("@If @*bar*@ Then End If",
new MarkupBlock(
Factory.EmptyHtml(),
new StatementBlock(
Factory.CodeTransition(),
Factory.Code("If ").AsStatement(),
new CommentBlock(
Factory.CodeTransition(VBSymbolType.RazorCommentTransition),
Factory.MetaCode("*", VBSymbolType.RazorCommentStar).Accepts(AcceptedCharacters.None),
Factory.Comment("bar", VBSymbolType.RazorComment),
Factory.MetaCode("*", VBSymbolType.RazorCommentStar).Accepts(AcceptedCharacters.None),
Factory.CodeTransition(VBSymbolType.RazorCommentTransition)),
Factory.Code(" Then End If").AsStatement().Accepts(AcceptedCharacters.None)),
Factory.EmptyHtml()));
}
[Fact]
public void BlockCommentInExplicitExpressionIsHandledCorrectly()
{
ParseDocumentTest(@"@(1 + @*bar*@ 1)",
new MarkupBlock(
Factory.EmptyHtml(),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.MetaCode("(").Accepts(AcceptedCharacters.None),
Factory.Code(@"1 + ").AsExpression(),
new CommentBlock(
Factory.CodeTransition(VBSymbolType.RazorCommentTransition),
Factory.MetaCode("*", VBSymbolType.RazorCommentStar).Accepts(AcceptedCharacters.None),
Factory.Comment("bar", VBSymbolType.RazorComment),
Factory.MetaCode("*", VBSymbolType.RazorCommentStar).Accepts(AcceptedCharacters.None),
Factory.CodeTransition(VBSymbolType.RazorCommentTransition)
),
Factory.Code(" 1").AsExpression(),
Factory.MetaCode(")").Accepts(AcceptedCharacters.None)
),
Factory.EmptyHtml()));
}
}
}

View File

@ -0,0 +1,79 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.Razor.Test.Parser.VB
{
public class VBImplicitExpressionTest : VBHtmlCodeParserTestBase
{
[Fact]
public void VB_Simple_ImplicitExpression()
{
ParseBlockTest("@foo not-part-of-the-block",
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("foo")
.AsImplicitExpression(VBCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)));
}
[Fact]
public void VB_ImplicitExpression_With_Keyword_At_Start()
{
ParseBlockTest("@Partial",
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("Partial")
.AsImplicitExpression(VBCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)));
}
[Fact]
public void VB_ImplicitExpression_With_Keyword_In_Body()
{
ParseBlockTest("@Html.Partial",
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("Html.Partial")
.AsImplicitExpression(VBCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)));
}
[Fact]
public void VB_ImplicitExpression_With_MethodCallOrArrayIndex()
{
ParseBlockTest("@foo(42) not-part-of-the-block",
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("foo(42)")
.AsImplicitExpression(VBCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)));
}
[Fact]
public void VB_ImplicitExpression_Terminates_If_Trailing_Dot_Not_Followed_By_Valid_Token()
{
ParseBlockTest("@foo(42). ",
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("foo(42)")
.AsImplicitExpression(VBCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)));
}
[Fact]
public void VB_ImplicitExpression_Supports_Complex_Expressions()
{
ParseBlockTest("@foo(42).bar(Biz.Boz / 42 * 8)(1).Burf not part of the block",
new ExpressionBlock(
Factory.CodeTransition()
.Accepts(AcceptedCharacters.None),
Factory.Code("foo(42).bar(Biz.Boz / 42 * 8)(1).Burf")
.AsImplicitExpression(VBCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)));
}
}
}

View File

@ -0,0 +1,87 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.Razor.Editor;
using Microsoft.AspNet.Razor.Generator;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.Razor.Test.Parser.VB
{
public class VBLayoutDirectiveTest : VBHtmlCodeParserTestBase
{
[Theory]
[InlineData("layout")]
[InlineData("Layout")]
[InlineData("LAYOUT")]
[InlineData("layOut")]
[InlineData("LayOut")]
[InlineData("LaYoUt")]
[InlineData("lAyOuT")]
public void LayoutDirectiveSupportsAnyCasingOfKeyword(string keyword)
{
ParseBlockTest("@" + keyword,
new DirectiveBlock(
Factory.CodeTransition(),
Factory.MetaCode(keyword)
)
);
}
[Fact]
public void LayoutDirectiveAcceptsAllTextToEndOfLine()
{
ParseBlockTest("@Layout Foo Bar Baz",
new DirectiveBlock(
Factory.CodeTransition(),
Factory.MetaCode("Layout ").Accepts(AcceptedCharacters.None),
Factory.MetaCode("Foo Bar Baz")
.With(new SetLayoutCodeGenerator("Foo Bar Baz"))
.WithEditorHints(EditorHints.VirtualPath | EditorHints.LayoutPage)
)
);
}
[Fact]
public void LayoutDirectiveAcceptsAnyIfNoWhitespaceFollowingLayoutKeyword()
{
ParseBlockTest("@Layout",
new DirectiveBlock(
Factory.CodeTransition(),
Factory.MetaCode("Layout")
)
);
}
[Fact]
public void LayoutDirectiveOutputsMarkerSpanIfAnyWhitespaceAfterLayoutKeyword()
{
ParseBlockTest("@Layout ",
new DirectiveBlock(
Factory.CodeTransition(),
Factory.MetaCode("Layout ").Accepts(AcceptedCharacters.None),
Factory.EmptyVB()
.AsMetaCode()
.With(new SetLayoutCodeGenerator(String.Empty))
.WithEditorHints(EditorHints.VirtualPath | EditorHints.LayoutPage)
)
);
}
[Fact]
public void LayoutDirectiveAcceptsTrailingNewlineButDoesNotIncludeItInLayoutPath()
{
ParseBlockTest("@Layout Foo" + Environment.NewLine,
new DirectiveBlock(
Factory.CodeTransition(),
Factory.MetaCode("Layout ").Accepts(AcceptedCharacters.None),
Factory.MetaCode("Foo\r\n")
.With(new SetLayoutCodeGenerator("Foo"))
.Accepts(AcceptedCharacters.None)
.WithEditorHints(EditorHints.VirtualPath | EditorHints.LayoutPage)
)
);
}
}
}

View File

@ -0,0 +1,170 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.AspNet.Razor.Tokenizer.Symbols;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.Razor.Test.Parser.VB
{
public class VBNestedStatementsTest : VBHtmlCodeParserTestBase
{
[Fact]
public void VB_Nested_If_Statement()
{
ParseBlockTest("@If True Then" + Environment.NewLine
+ " If False Then" + Environment.NewLine
+ " End If" + Environment.NewLine
+ "End If",
new StatementBlock(
Factory.CodeTransition(),
Factory.Code("If True Then\r\n If False Then\r\n End If\r\nEnd If")
.AsStatement()
.Accepts(AcceptedCharacters.None)));
}
[Fact]
public void VB_Nested_Do_Statement()
{
ParseBlockTest("@Do While True" + Environment.NewLine
+ " Do" + Environment.NewLine
+ " Loop Until False" + Environment.NewLine
+ "Loop",
new StatementBlock(
Factory.CodeTransition(),
Factory.Code("Do While True\r\n Do\r\n Loop Until False\r\nLoop")
.AsStatement()
.Accepts(AcceptedCharacters.AnyExceptNewline)));
}
[Fact]
public void VB_Nested_Markup_Statement_In_If()
{
ParseBlockTest("@If True Then" + Environment.NewLine
+ " @<p>Tag</p>" + Environment.NewLine
+ "End If",
new StatementBlock(
Factory.CodeTransition(),
Factory.Code("If True Then\r\n")
.AsStatement(),
new MarkupBlock(
Factory.Markup(" "),
Factory.MarkupTransition(),
Factory.Markup("<p>Tag</p>\r\n")
.Accepts(AcceptedCharacters.None)),
Factory.Code("End If")
.AsStatement()
.Accepts(AcceptedCharacters.None)));
}
[Fact]
public void VB_Nested_Markup_Statement_In_Code()
{
ParseBlockTest("@Code" + Environment.NewLine
+ " Foo()" + Environment.NewLine
+ " @<p>Tag</p>" + Environment.NewLine
+ " Bar()" + Environment.NewLine
+ "End Code",
new StatementBlock(
Factory.CodeTransition(),
Factory.MetaCode("Code")
.Accepts(AcceptedCharacters.None),
Factory.Code("\r\n Foo()\r\n")
.AsStatement(),
new MarkupBlock(
Factory.Markup(" "),
Factory.MarkupTransition(),
Factory.Markup("<p>Tag</p>\r\n")
.Accepts(AcceptedCharacters.None)),
Factory.Code(" Bar()\r\n")
.AsStatement(),
Factory.MetaCode("End Code")
.Accepts(AcceptedCharacters.None)));
}
[Fact]
public void VB_Nested_Markup_Statement_In_Do()
{
ParseBlockTest("@Do" + Environment.NewLine
+ " @<p>Tag</p>" + Environment.NewLine
+ "Loop While True",
new StatementBlock(
Factory.CodeTransition(),
Factory.Code("Do\r\n")
.AsStatement(),
new MarkupBlock(
Factory.Markup(" "),
Factory.MarkupTransition(),
Factory.Markup("<p>Tag</p>\r\n")
.Accepts(AcceptedCharacters.None)),
Factory.Code("Loop While True")
.AsStatement()
.Accepts(AcceptedCharacters.AnyExceptNewline)));
}
[Fact]
public void VB_Nested_Single_Line_Markup_Statement_In_Do()
{
ParseBlockTest("@Do" + Environment.NewLine
+ " @:<p>Tag" + Environment.NewLine
+ "Loop While True",
new StatementBlock(
Factory.CodeTransition(),
Factory.Code("Do\r\n")
.AsStatement(),
new MarkupBlock(
Factory.Markup(" "),
Factory.MarkupTransition(),
Factory.MetaMarkup(":", HtmlSymbolType.Colon),
Factory.Markup("<p>Tag\r\n")
.Accepts(AcceptedCharacters.None)),
Factory.Code("Loop While True")
.AsStatement()
.Accepts(AcceptedCharacters.AnyExceptNewline)));
}
[Fact]
public void VB_Nested_Implicit_Expression_In_If()
{
ParseBlockTest("@If True Then" + Environment.NewLine
+ " @Foo.Bar" + Environment.NewLine
+ "End If",
new StatementBlock(
Factory.CodeTransition(),
Factory.Code("If True Then\r\n ")
.AsStatement(),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("Foo.Bar")
.AsExpression()
.Accepts(AcceptedCharacters.NonWhiteSpace)),
Factory.Code("\r\nEnd If")
.AsStatement()
.Accepts(AcceptedCharacters.None)));
}
[Fact]
public void VB_Nested_Explicit_Expression_In_If()
{
ParseBlockTest("@If True Then" + Environment.NewLine
+ " @(Foo.Bar + 42)" + Environment.NewLine
+ "End If",
new StatementBlock(
Factory.CodeTransition(),
Factory.Code("If True Then\r\n ")
.AsStatement(),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.MetaCode("(")
.Accepts(AcceptedCharacters.None),
Factory.Code("Foo.Bar + 42")
.AsExpression(),
Factory.MetaCode(")")
.Accepts(AcceptedCharacters.None)),
Factory.Code("\r\nEnd If")
.AsStatement()
.Accepts(AcceptedCharacters.None)));
}
}
}

View File

@ -0,0 +1,175 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Resources;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.AspNet.Razor.Tokenizer.Symbols;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.Razor.Test.Parser.VB
{
public class VBRazorCommentsTest : VBHtmlMarkupParserTestBase
{
[Fact]
public void UnterminatedRazorComment()
{
ParseDocumentTest("@*",
new MarkupBlock(
Factory.EmptyHtml(),
new CommentBlock(
Factory.MarkupTransition(HtmlSymbolType.RazorCommentTransition)
.Accepts(AcceptedCharacters.None),
Factory.MetaMarkup("*", HtmlSymbolType.RazorCommentStar)
.Accepts(AcceptedCharacters.None),
Factory.Span(SpanKind.Comment, new HtmlSymbol(
Factory.LocationTracker.CurrentLocation,
String.Empty,
HtmlSymbolType.Unknown))
.Accepts(AcceptedCharacters.Any))),
new RazorError(RazorResources.ParseError_RazorComment_Not_Terminated, 0, 0, 0));
}
[Fact]
public void EmptyRazorComment()
{
ParseDocumentTest("@**@",
new MarkupBlock(
Factory.EmptyHtml(),
new CommentBlock(
Factory.MarkupTransition(HtmlSymbolType.RazorCommentTransition)
.Accepts(AcceptedCharacters.None),
Factory.MetaMarkup("*", HtmlSymbolType.RazorCommentStar)
.Accepts(AcceptedCharacters.None),
Factory.Span(SpanKind.Comment, new HtmlSymbol(
Factory.LocationTracker.CurrentLocation,
String.Empty,
HtmlSymbolType.Unknown))
.Accepts(AcceptedCharacters.Any),
Factory.MetaMarkup("*", HtmlSymbolType.RazorCommentStar)
.Accepts(AcceptedCharacters.None),
Factory.MarkupTransition(HtmlSymbolType.RazorCommentTransition)
.Accepts(AcceptedCharacters.None)),
Factory.EmptyHtml()));
}
[Fact]
public void RazorCommentInImplicitExpressionMethodCall()
{
ParseDocumentTest(@"@foo(@**@",
new MarkupBlock(
Factory.EmptyHtml(),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("foo(")
.AsImplicitExpression(VBCodeParser.DefaultKeywords),
new CommentBlock(
Factory.CodeTransition(VBSymbolType.RazorCommentTransition)
.Accepts(AcceptedCharacters.None),
Factory.MetaCode("*", VBSymbolType.RazorCommentStar)
.Accepts(AcceptedCharacters.None),
Factory.Span(SpanKind.Comment, new VBSymbol(
Factory.LocationTracker.CurrentLocation,
String.Empty,
VBSymbolType.Unknown))
.Accepts(AcceptedCharacters.Any),
Factory.MetaCode("*", VBSymbolType.RazorCommentStar)
.Accepts(AcceptedCharacters.None),
Factory.CodeTransition(VBSymbolType.RazorCommentTransition)
.Accepts(AcceptedCharacters.None)),
Factory.EmptyVB()
.AsImplicitExpression(VBCodeParser.DefaultKeywords))),
new RazorError(
String.Format(RazorResources.ParseError_Expected_CloseBracket_Before_EOF, "(", ")"),
4, 0, 4));
}
[Fact]
public void UnterminatedRazorCommentInImplicitExpressionMethodCall()
{
ParseDocumentTest("@foo(@*",
new MarkupBlock(
Factory.EmptyHtml(),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("foo(")
.AsImplicitExpression(VBCodeParser.DefaultKeywords),
new CommentBlock(
Factory.CodeTransition(VBSymbolType.RazorCommentTransition)
.Accepts(AcceptedCharacters.None),
Factory.MetaCode("*", VBSymbolType.RazorCommentStar)
.Accepts(AcceptedCharacters.None),
Factory.Span(SpanKind.Comment, new VBSymbol(
Factory.LocationTracker.CurrentLocation,
String.Empty,
VBSymbolType.Unknown))
.Accepts(AcceptedCharacters.Any)))),
new RazorError(RazorResources.ParseError_RazorComment_Not_Terminated, 5, 0, 5),
new RazorError(String.Format(RazorResources.ParseError_Expected_CloseBracket_Before_EOF, "(", ")"), 4, 0, 4));
}
[Fact]
public void RazorCommentInVerbatimBlock()
{
ParseDocumentTest("@Code" + Environment.NewLine
+ " @<text" + Environment.NewLine
+ " @**@" + Environment.NewLine
+ "End Code",
new MarkupBlock(
Factory.EmptyHtml(),
new StatementBlock(
Factory.CodeTransition(),
Factory.MetaCode("Code").Accepts(AcceptedCharacters.None),
Factory.Code("\r\n").AsStatement(),
new MarkupBlock(
Factory.Markup(" "),
Factory.MarkupTransition("@"),
Factory.MarkupTransition("<text").Accepts(AcceptedCharacters.Any),
Factory.Markup("\r\n "),
new CommentBlock(
Factory.MarkupTransition(HtmlSymbolType.RazorCommentTransition)
.Accepts(AcceptedCharacters.None),
Factory.MetaMarkup("*", HtmlSymbolType.RazorCommentStar)
.Accepts(AcceptedCharacters.None),
Factory.Span(SpanKind.Comment, new HtmlSymbol(
Factory.LocationTracker.CurrentLocation,
String.Empty,
HtmlSymbolType.Unknown))
.Accepts(AcceptedCharacters.Any),
Factory.MetaMarkup("*", HtmlSymbolType.RazorCommentStar)
.Accepts(AcceptedCharacters.None),
Factory.MarkupTransition(HtmlSymbolType.RazorCommentTransition)
.Accepts(AcceptedCharacters.None)),
Factory.Markup("\r\nEnd Code")))),
new RazorError(RazorResources.ParseError_TextTagCannotContainAttributes, 12, 1, 5),
new RazorError(String.Format(RazorResources.ParseError_MissingEndTag, "text"), 12, 1, 5),
new RazorError(String.Format(RazorResources.ParseError_BlockNotTerminated, SyntaxConstants.VB.CodeKeyword, SyntaxConstants.VB.EndCodeKeyword), 1, 0, 1));
}
[Fact]
public void UnterminatedRazorCommentInVerbatimBlock()
{
ParseDocumentTest("@Code" + Environment.NewLine
+ "@*",
new MarkupBlock(
Factory.EmptyHtml(),
new StatementBlock(
Factory.CodeTransition(),
Factory.MetaCode("Code").Accepts(AcceptedCharacters.None),
Factory.Code("\r\n")
.AsStatement(),
new CommentBlock(
Factory.CodeTransition(VBSymbolType.RazorCommentTransition)
.Accepts(AcceptedCharacters.None),
Factory.MetaCode("*", VBSymbolType.RazorCommentStar)
.Accepts(AcceptedCharacters.None),
Factory.Span(SpanKind.Comment, new VBSymbol(Factory.LocationTracker.CurrentLocation,
String.Empty,
VBSymbolType.Unknown))
.Accepts(AcceptedCharacters.Any)))),
new RazorError(RazorResources.ParseError_RazorComment_Not_Terminated, 7, 1, 0),
new RazorError(String.Format(RazorResources.ParseError_BlockNotTerminated, SyntaxConstants.VB.CodeKeyword, SyntaxConstants.VB.EndCodeKeyword), 1, 0, 1));
}
}
}

View File

@ -0,0 +1,31 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Resources;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.AspNet.Razor.Text;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.Razor.Test.Parser.VB
{
public class VBReservedWordsTest : VBHtmlCodeParserTestBase
{
[Theory]
[InlineData("Namespace")]
[InlineData("Class")]
[InlineData("NAMESPACE")]
[InlineData("CLASS")]
[InlineData("NameSpace")]
[InlineData("nameSpace")]
private void ReservedWords(string word)
{
ParseBlockTest(word,
new DirectiveBlock(
Factory.MetaCode(word).Accepts(AcceptedCharacters.None)),
new RazorError(
String.Format(RazorResources.ParseError_ReservedWord, word),
SourceLocation.Zero));
}
}
}

View File

@ -0,0 +1,277 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.Razor.Generator;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Resources;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.Razor.Test.Parser.VB
{
public class VBSectionTest : VBHtmlMarkupParserTestBase
{
[Fact]
public void ParseSectionBlockCapturesNewlineImmediatelyFollowing()
{
ParseDocumentTest("@Section" + Environment.NewLine,
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionCodeGenerator(String.Empty),
Factory.CodeTransition(),
Factory.MetaCode("Section\r\n"),
new MarkupBlock())),
new RazorError(
String.Format(
RazorResources.ParseError_Unexpected_Character_At_Section_Name_Start,
RazorResources.ErrorComponent_EndOfFile),
10, 1, 0),
new RazorError(
String.Format(
RazorResources.ParseError_BlockNotTerminated,
"Section", "End Section"),
1, 0, 1));
}
[Fact]
public void ParseSectionRequiresNameBeOnSameLineAsSectionKeyword()
{
ParseDocumentTest("@Section " + Environment.NewLine
+ "Foo" + Environment.NewLine
+ " <p>Body</p>" + Environment.NewLine
+ "End Section",
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionCodeGenerator(String.Empty),
Factory.CodeTransition(),
Factory.MetaCode("Section "),
new MarkupBlock(
Factory.Markup("\r\nFoo\r\n <p>Body</p>\r\n")),
Factory.MetaCode("End Section").Accepts(AcceptedCharacters.None)),
Factory.EmptyHtml()),
new RazorError(
String.Format(
RazorResources.ParseError_Unexpected_Character_At_Section_Name_Start,
RazorResources.ErrorComponent_Newline),
9, 0, 9));
}
[Fact]
public void ParseSectionAllowsNameToBeOnDifferentLineAsSectionKeywordIfUnderscoresUsed()
{
ParseDocumentTest("@Section _" + Environment.NewLine
+ "_" + Environment.NewLine
+ "Foo" + Environment.NewLine
+ " <p>Body</p>" + Environment.NewLine
+ "End Section",
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionCodeGenerator("Foo"),
Factory.CodeTransition(),
Factory.MetaCode("Section _\r\n_\r\nFoo"),
new MarkupBlock(
Factory.Markup("\r\n <p>Body</p>\r\n")),
Factory.MetaCode("End Section").Accepts(AcceptedCharacters.None)),
Factory.EmptyHtml()));
}
[Fact]
public void ParseSectionReportsErrorAndTerminatesSectionBlockIfKeywordNotFollowedByIdentifierStartCharacter()
{
ParseDocumentTest("@Section 9" + Environment.NewLine
+ " <p>Foo</p>" + Environment.NewLine
+ "End Section",
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionCodeGenerator(String.Empty),
Factory.CodeTransition(),
Factory.MetaCode("Section "),
new MarkupBlock(
Factory.Markup("9\r\n <p>Foo</p>\r\n")),
Factory.MetaCode("End Section").Accepts(AcceptedCharacters.None)),
Factory.EmptyHtml()),
new RazorError(
String.Format(
RazorResources.ParseError_Unexpected_Character_At_Section_Name_Start,
String.Format(RazorResources.ErrorComponent_Character, "9")),
9, 0, 9));
}
[Fact]
public void ParserOutputsErrorOnNestedSections()
{
ParseDocumentTest("@Section foo" + Environment.NewLine
+ " @Section bar" + Environment.NewLine
+ " <p>Foo</p>" + Environment.NewLine
+ " End Section" + Environment.NewLine
+ "End Section",
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionCodeGenerator("foo"),
Factory.CodeTransition(),
Factory.MetaCode("Section foo"),
new MarkupBlock(
Factory.Markup("\r\n"),
new SectionBlock(new SectionCodeGenerator("bar"),
Factory.Code(" ").AsStatement(),
Factory.CodeTransition(),
Factory.MetaCode("Section bar"),
new MarkupBlock(
Factory.Markup("\r\n <p>Foo</p>\r\n ")),
Factory.MetaCode("End Section").Accepts(AcceptedCharacters.None)),
Factory.Markup("\r\n")),
Factory.MetaCode("End Section").Accepts(AcceptedCharacters.None)),
Factory.EmptyHtml()),
new RazorError(
String.Format(
RazorResources.ParseError_Sections_Cannot_Be_Nested,
RazorResources.SectionExample_VB),
26, 1, 12));
}
[Fact]
public void ParseSectionHandlesEOFAfterIdentifier()
{
ParseDocumentTest("@Section foo",
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionCodeGenerator("foo"),
Factory.CodeTransition(),
Factory.MetaCode("Section foo")
.AutoCompleteWith(SyntaxConstants.VB.EndSectionKeyword),
new MarkupBlock())),
new RazorError(
String.Format(
RazorResources.ParseError_BlockNotTerminated,
"Section", "End Section"),
1, 0, 1));
}
[Fact]
public void ParseSectionHandlesUnterminatedSection()
{
ParseDocumentTest("@Section foo" + Environment.NewLine
+ " <p>Foo</p>",
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionCodeGenerator("foo"),
Factory.CodeTransition(),
Factory.MetaCode("Section foo")
.AutoCompleteWith(SyntaxConstants.VB.EndSectionKeyword),
new MarkupBlock(
Factory.Markup("\r\n <p>Foo</p>")))),
new RazorError(
String.Format(
RazorResources.ParseError_BlockNotTerminated,
"Section", "End Section"),
1, 0, 1));
}
[Fact]
public void ParseDocumentParsesNamedSectionCorrectly()
{
ParseDocumentTest("@Section foo" + Environment.NewLine
+ " <p>Foo</p>" + Environment.NewLine
+ "End Section",
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionCodeGenerator("foo"),
Factory.CodeTransition(),
Factory.MetaCode("Section foo"),
new MarkupBlock(
Factory.Markup("\r\n <p>Foo</p>\r\n")),
Factory.MetaCode("End Section").Accepts(AcceptedCharacters.None)),
Factory.EmptyHtml()));
}
[Fact]
public void ParseSectionTerminatesOnFirstEndSection()
{
ParseDocumentTest("@Section foo" + Environment.NewLine
+ " <p>End Section</p>",
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionCodeGenerator("foo"),
Factory.CodeTransition(),
Factory.MetaCode("Section foo"),
new MarkupBlock(
Factory.Markup("\r\n <p>")),
Factory.MetaCode("End Section").Accepts(AcceptedCharacters.None)),
Factory.Markup("</p>")));
}
[Fact]
public void ParseSectionAllowsEndSectionInVBExpression()
{
ParseDocumentTest("@Section foo" + Environment.NewLine
+ " I really want to render the word @(\"End Section\"), so this is how I do it" + Environment.NewLine
+ "End Section",
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionCodeGenerator("foo"),
Factory.CodeTransition(),
Factory.MetaCode("Section foo"),
new MarkupBlock(
Factory.Markup("\r\n I really want to render the word "),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.MetaCode("(").Accepts(AcceptedCharacters.None),
Factory.Code("\"End Section\"").AsExpression(),
Factory.MetaCode(")").Accepts(AcceptedCharacters.None)),
Factory.Markup(", so this is how I do it\r\n")),
Factory.MetaCode("End Section").Accepts(AcceptedCharacters.None)),
Factory.EmptyHtml()));
}
// These are tests that are normally in HtmlToCodeSwitchTest, but we want to verify them for VB
// since VB has slightly different section terminating behavior which follow slightly different
// code paths
[Fact]
public void SectionBodyTreatsTwoAtSignsAsEscapeSequence()
{
ParseDocumentTest("@Section Foo" + Environment.NewLine
+ " <foo>@@bar</foo>" + Environment.NewLine
+ "End Section",
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionCodeGenerator("Foo"),
Factory.CodeTransition(),
Factory.MetaCode("Section Foo").AutoCompleteWith(null),
new MarkupBlock(
Factory.Markup("\r\n <foo>"),
Factory.Markup("@").Hidden(),
Factory.Markup("@bar</foo>\r\n")),
Factory.MetaCode("End Section").Accepts(AcceptedCharacters.None)),
Factory.EmptyHtml()));
}
[Fact]
public void SectionBodyTreatsPairsOfAtSignsAsEscapeSequence()
{
ParseDocumentTest("@Section Foo" + Environment.NewLine
+ " <foo>@@@@@bar</foo>" + Environment.NewLine
+ "End Section",
new MarkupBlock(
Factory.EmptyHtml(),
new SectionBlock(new SectionCodeGenerator("Foo"),
Factory.CodeTransition(),
Factory.MetaCode("Section Foo").AutoCompleteWith(null),
new MarkupBlock(
Factory.Markup("\r\n <foo>"),
Factory.Markup("@").Hidden(),
Factory.Markup("@"),
Factory.Markup("@").Hidden(),
Factory.Markup("@"),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("bar")
.AsImplicitExpression(VBCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
Factory.Markup("</foo>\r\n")),
Factory.MetaCode("End Section").Accepts(AcceptedCharacters.None)),
Factory.EmptyHtml()));
}
}
}

View File

@ -0,0 +1,172 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.Razor.Generator;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Resources;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.Razor.Test.Parser.VB
{
public class VBSpecialKeywordsTest : VBHtmlCodeParserTestBase
{
[Fact]
public void ParseInheritsStatementMarksInheritsSpanAsCanGrowIfMissingTrailingSpace()
{
ParseBlockTest("inherits",
new DirectiveBlock(
Factory.MetaCode("inherits")),
new RazorError(
RazorResources.ParseError_InheritsKeyword_Must_Be_Followed_By_TypeName,
8, 0, 8));
}
[Fact]
public void InheritsBlockAcceptsMultipleGenericArguments()
{
ParseBlockTest("inherits Foo.Bar(Of Biz(Of Qux), String, Integer).Baz",
new DirectiveBlock(
Factory.MetaCode("inherits ").Accepts(AcceptedCharacters.None),
Factory.Code("Foo.Bar(Of Biz(Of Qux), String, Integer).Baz")
.AsBaseType("Foo.Bar(Of Biz(Of Qux), String, Integer).Baz")));
}
[Fact]
public void InheritsDirectiveSupportsVSTemplateTokens()
{
ParseBlockTest("@Inherits $rootnamespace$.MyBase",
new DirectiveBlock(
Factory.CodeTransition(),
Factory.MetaCode("Inherits ")
.Accepts(AcceptedCharacters.None),
Factory.Code("$rootnamespace$.MyBase")
.AsBaseType("$rootnamespace$.MyBase")));
}
[Fact]
public void InheritsBlockOutputsErrorIfInheritsNotFollowedByTypeButAcceptsEntireLineAsCode()
{
ParseBlockTest("inherits " + Environment.NewLine
+ "foo",
new DirectiveBlock(
Factory.MetaCode("inherits ").Accepts(AcceptedCharacters.None),
Factory.Code("\r\n").AsBaseType(String.Empty)),
new RazorError(
RazorResources.ParseError_InheritsKeyword_Must_Be_Followed_By_TypeName,
8, 0, 8));
}
[Fact]
public void ParseBlockShouldSupportNamespaceImports()
{
ParseBlockTest("Imports Foo.Bar.Baz.Biz.Boz",
new DirectiveBlock(
Factory.MetaCode("Imports Foo.Bar.Baz.Biz.Boz")
.With(new AddImportCodeGenerator(
ns: " Foo.Bar.Baz.Biz.Boz",
namespaceKeywordLength: SyntaxConstants.VB.ImportsKeywordLength))));
}
[Fact]
public void ParseBlockShowsErrorIfNamespaceNotOnSameLineAsImportsKeyword()
{
ParseBlockTest("Imports" + Environment.NewLine
+ "Foo",
new DirectiveBlock(
Factory.MetaCode("Imports\r\n")
.With(new AddImportCodeGenerator(
ns: "\r\n",
namespaceKeywordLength: SyntaxConstants.VB.ImportsKeywordLength))),
new RazorError(
RazorResources.ParseError_NamespaceOrTypeAliasExpected,
7, 0, 7));
}
[Fact]
public void ParseBlockShowsErrorIfTypeBeingAliasedNotOnSameLineAsImportsKeyword()
{
ParseBlockTest("Imports Foo =" + Environment.NewLine
+ "System.Bar",
new DirectiveBlock(
Factory.MetaCode("Imports Foo =\r\n")
.With(new AddImportCodeGenerator(
ns: " Foo =\r\n",
namespaceKeywordLength: SyntaxConstants.VB.ImportsKeywordLength))));
}
[Fact]
public void ParseBlockShouldSupportTypeAliases()
{
ParseBlockTest("Imports Foo = Bar.Baz.Biz.Boz",
new DirectiveBlock(
Factory.MetaCode("Imports Foo = Bar.Baz.Biz.Boz")
.With(new AddImportCodeGenerator(
ns: " Foo = Bar.Baz.Biz.Boz",
namespaceKeywordLength: SyntaxConstants.VB.ImportsKeywordLength))));
}
[Fact]
public void ParseBlockThrowsErrorIfOptionIsNotFollowedByStrictOrExplicit()
{
ParseBlockTest("Option FizzBuzz On",
new DirectiveBlock(
Factory.MetaCode("Option FizzBuzz On")
.With(new SetVBOptionCodeGenerator(optionName: null, value: true))),
new RazorError(
String.Format(RazorResources.ParseError_UnknownOption, "FizzBuzz"),
7, 0, 7));
}
[Fact]
public void ParseBlockThrowsErrorIfOptionStrictIsNotFollowedByOnOrOff()
{
ParseBlockTest("Option Strict Yes",
new DirectiveBlock(
Factory.MetaCode("Option Strict Yes")
.With(SetVBOptionCodeGenerator.Strict(true))),
new RazorError(
String.Format(
RazorResources.ParseError_InvalidOptionValue,
"Strict", "Yes"),
14, 0, 14));
}
[Fact]
public void ParseBlockReadsToAfterOnKeywordIfOptionStrictBlock()
{
ParseBlockTest("Option Strict On Foo Bar Baz",
new DirectiveBlock(
Factory.MetaCode("Option Strict On")
.With(SetVBOptionCodeGenerator.Strict(true))));
}
[Fact]
public void ParseBlockReadsToAfterOffKeywordIfOptionStrictBlock()
{
ParseBlockTest("Option Strict Off Foo Bar Baz",
new DirectiveBlock(
Factory.MetaCode("Option Strict Off")
.With(SetVBOptionCodeGenerator.Strict(false))));
}
[Fact]
public void ParseBlockReadsToAfterOnKeywordIfOptionExplicitBlock()
{
ParseBlockTest("Option Explicit On Foo Bar Baz",
new DirectiveBlock(
Factory.MetaCode("Option Explicit On")
.With(SetVBOptionCodeGenerator.Explicit(true))));
}
[Fact]
public void ParseBlockReadsToAfterOffKeywordIfOptionExplicitBlock()
{
ParseBlockTest("Option Explicit Off Foo Bar Baz",
new DirectiveBlock(
Factory.MetaCode("Option Explicit Off")
.With(SetVBOptionCodeGenerator.Explicit(false))));
}
}
}

View File

@ -0,0 +1,221 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.Razor.Generator;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.Razor.Test.Parser.VB
{
public class VBStatementTest : VBHtmlCodeParserTestBase
{
[Fact]
public void VB_Inherits_Statement()
{
ParseBlockTest("@Inherits System.Foo.Bar(Of Baz)",
new DirectiveBlock(
Factory.CodeTransition(),
Factory.MetaCode("Inherits ").Accepts(AcceptedCharacters.None),
Factory.Code("System.Foo.Bar(Of Baz)")
.AsBaseType("System.Foo.Bar(Of Baz)")));
}
[Fact]
public void InheritsDirectiveSupportsArrays()
{
ParseBlockTest("@Inherits System.String(())()",
new DirectiveBlock(
Factory.CodeTransition(),
Factory.MetaCode("Inherits ")
.Accepts(AcceptedCharacters.None),
Factory.Code("System.String(())()")
.AsBaseType("System.String(())()")));
}
[Fact]
public void InheritsDirectiveSupportsNestedGenerics()
{
ParseBlockTest("@Inherits System.Web.Mvc.WebViewPage(Of IEnumerable(Of MvcApplication2.Models.RegisterModel))",
new DirectiveBlock(
Factory.CodeTransition(),
Factory.MetaCode("Inherits ")
.Accepts(AcceptedCharacters.None),
Factory.Code("System.Web.Mvc.WebViewPage(Of IEnumerable(Of MvcApplication2.Models.RegisterModel))")
.AsBaseType("System.Web.Mvc.WebViewPage(Of IEnumerable(Of MvcApplication2.Models.RegisterModel))")));
}
[Fact]
public void InheritsDirectiveSupportsTypeKeywords()
{
ParseBlockTest("@Inherits String",
new DirectiveBlock(
Factory.CodeTransition(),
Factory.MetaCode("Inherits ").Accepts(AcceptedCharacters.None),
Factory.Code("String").AsBaseType("String")));
}
[Fact]
public void VB_Option_Strict_Statement()
{
ParseBlockTest("@Option Strict Off",
new DirectiveBlock(
Factory.CodeTransition(),
Factory.MetaCode("Option Strict Off")
.With(SetVBOptionCodeGenerator.Strict(false))));
}
[Fact]
public void VB_Option_Explicit_Statement()
{
ParseBlockTest("@Option Explicit Off",
new DirectiveBlock(
Factory.CodeTransition(),
Factory.MetaCode("Option Explicit Off")
.With(SetVBOptionCodeGenerator.Explicit(false))));
}
[Fact]
public void VB_Imports_Statement()
{
ParseBlockTest("@Imports Biz = System.Foo.Bar(Of Boz.Baz(Of Qux))",
new DirectiveBlock(
Factory.CodeTransition(),
Factory.MetaCode("Imports Biz = System.Foo.Bar(Of Boz.Baz(Of Qux))")
.With(new AddImportCodeGenerator(
ns: " Biz = System.Foo.Bar(Of Boz.Baz(Of Qux))",
namespaceKeywordLength: SyntaxConstants.VB.ImportsKeywordLength))));
}
[Fact]
public void VB_Using_Statement()
{
ParseBlockTest("@Using foo as Bar" + Environment.NewLine
+ " foo()" + Environment.NewLine
+ "End Using",
new StatementBlock(
Factory.CodeTransition(),
Factory.Code("Using foo as Bar\r\n foo()\r\nEnd Using")
.AsStatement()
.Accepts(AcceptedCharacters.None)));
}
[Fact]
public void VB_Do_Loop_Statement()
{
ParseBlockTest("@Do" + Environment.NewLine
+ " foo()" + Environment.NewLine
+ "Loop While True",
new StatementBlock(
Factory.CodeTransition(),
Factory.Code("Do\r\n foo()\r\nLoop While True")
.AsStatement()
.Accepts(AcceptedCharacters.AnyExceptNewline)));
}
[Fact]
public void VB_While_Statement()
{
ParseBlockTest("@While True" + Environment.NewLine
+ " foo()" + Environment.NewLine
+ "End While",
new StatementBlock(
Factory.CodeTransition(),
Factory.Code("While True\r\n foo()\r\nEnd While")
.AsStatement()
.Accepts(AcceptedCharacters.None)));
}
[Fact]
public void VB_If_Statement()
{
ParseBlockTest("@If True Then" + Environment.NewLine
+ " foo()" + Environment.NewLine
+ "ElseIf False Then" + Environment.NewLine
+ " bar()" + Environment.NewLine
+ "Else" + Environment.NewLine
+ " baz()" + Environment.NewLine
+ "End If",
new StatementBlock(
Factory.CodeTransition(),
Factory.Code("If True Then\r\n foo()\r\nElseIf False Then\r\n bar()\r\nElse\r\n baz()\r\nEnd If")
.AsStatement()
.Accepts(AcceptedCharacters.None)));
}
[Fact]
public void VB_Select_Statement()
{
ParseBlockTest("@Select Case foo" + Environment.NewLine
+ " Case 1" + Environment.NewLine
+ " foo()" + Environment.NewLine
+ " Case 2" + Environment.NewLine
+ " bar()" + Environment.NewLine
+ " Case Else" + Environment.NewLine
+ " baz()" + Environment.NewLine
+ "End Select",
new StatementBlock(
Factory.CodeTransition(),
Factory.Code("Select Case foo\r\n Case 1\r\n foo()\r\n Case 2\r\n bar()\r\n Case Else\r\n baz()\r\nEnd Select")
.AsStatement()
.Accepts(AcceptedCharacters.None)));
}
[Fact]
public void VB_For_Statement()
{
ParseBlockTest("@For Each foo In bar" + Environment.NewLine
+ " baz()" + Environment.NewLine
+ "Next",
new StatementBlock(
Factory.CodeTransition(),
Factory.Code("For Each foo In bar\r\n baz()\r\nNext")
.AsStatement()
.Accepts(AcceptedCharacters.AnyExceptNewline)));
}
[Fact]
public void VB_Try_Statement()
{
ParseBlockTest("@Try" + Environment.NewLine
+ " foo()" + Environment.NewLine
+ "Catch ex as Exception" + Environment.NewLine
+ " bar()" + Environment.NewLine
+ "Finally" + Environment.NewLine
+ " baz()" + Environment.NewLine
+ "End Try",
new StatementBlock(
Factory.CodeTransition(),
Factory.Code("Try\r\n foo()\r\nCatch ex as Exception\r\n bar()\r\nFinally\r\n baz()\r\nEnd Try")
.AsStatement()
.Accepts(AcceptedCharacters.None)));
}
[Fact]
public void VB_With_Statement()
{
ParseBlockTest("@With foo" + Environment.NewLine
+ " .bar()" + Environment.NewLine
+ "End With",
new StatementBlock(
Factory.CodeTransition(),
Factory.Code("With foo\r\n .bar()\r\nEnd With")
.AsStatement()
.Accepts(AcceptedCharacters.None)));
}
[Fact]
public void VB_SyncLock_Statement()
{
ParseBlockTest("@SyncLock foo" + Environment.NewLine
+ " foo.bar()" + Environment.NewLine
+ "End SyncLock",
new StatementBlock(
Factory.CodeTransition(),
Factory.Code("SyncLock foo\r\n foo.bar()\r\nEnd SyncLock")
.AsStatement()
.Accepts(AcceptedCharacters.None)));
}
}
}

View File

@ -0,0 +1,214 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.Razor.Generator;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Resources;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.Razor.Test.Parser.VB
{
public class VBTemplateTest : VBHtmlCodeParserTestBase
{
private const string TestTemplateCode = "@@<p>Foo #@item</p>";
private TemplateBlock TestTemplate()
{
return new TemplateBlock(new TemplateBlockCodeGenerator(),
new MarkupBlock(
Factory.MarkupTransition(),
Factory.MetaMarkup("@"),
Factory.Markup("<p>Foo #"),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("item")
.AsImplicitExpression(VBCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
Factory.Markup("</p>").Accepts(AcceptedCharacters.None)));
}
private const string TestNestedTemplateCode = "@@<p>Foo #@Html.Repeat(10,@@<p>@item</p>)</p>";
private TemplateBlock TestNestedTemplate()
{
return new TemplateBlock(new TemplateBlockCodeGenerator(),
new MarkupBlock(
Factory.MarkupTransition(),
Factory.MetaMarkup("@"),
Factory.Markup("<p>Foo #"),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("Html.Repeat(10,")
.AsImplicitExpression(VBCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.Any),
new TemplateBlock(new TemplateBlockCodeGenerator(),
new MarkupBlock(
Factory.MarkupTransition(),
Factory.MetaMarkup("@"),
Factory.Markup("<p>"),
new ExpressionBlock(
Factory.CodeTransition(),
Factory.Code("item")
.AsImplicitExpression(VBCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
Factory.Markup("</p>").Accepts(AcceptedCharacters.None))),
Factory.Code(")")
.AsImplicitExpression(VBCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)),
Factory.Markup("</p>").Accepts(AcceptedCharacters.None)));
}
[Fact]
public void ParseBlockHandlesSimpleAnonymousSectionInExplicitExpressionParens()
{
ParseBlockTest("(Html.Repeat(10," + TestTemplateCode + "))",
new ExpressionBlock(
Factory.MetaCode("(").Accepts(AcceptedCharacters.None),
Factory.Code("Html.Repeat(10,").AsExpression(),
TestTemplate(),
Factory.Code(")").AsExpression(),
Factory.MetaCode(")").Accepts(AcceptedCharacters.None)));
}
[Fact]
public void ParseBlockHandlesSimpleAnonymousSectionInImplicitExpressionParens()
{
ParseBlockTest("Html.Repeat(10," + TestTemplateCode + ")",
new ExpressionBlock(
Factory.Code("Html.Repeat(10,").AsImplicitExpression(KeywordSet),
TestTemplate(),
Factory.Code(")").AsImplicitExpression(KeywordSet).Accepts(AcceptedCharacters.NonWhiteSpace)));
}
[Fact]
public void ParseBlockHandlesTwoAnonymousSectionsInImplicitExpressionParens()
{
ParseBlockTest("Html.Repeat(10," + TestTemplateCode + "," + TestTemplateCode + ")",
new ExpressionBlock(
Factory.Code("Html.Repeat(10,").AsImplicitExpression(KeywordSet),
TestTemplate(),
Factory.Code(",").AsImplicitExpression(KeywordSet),
TestTemplate(),
Factory.Code(")").AsImplicitExpression(KeywordSet).Accepts(AcceptedCharacters.NonWhiteSpace)));
}
[Fact]
public void ParseBlockProducesErrorButCorrectlyParsesNestedAnonymousSectionInImplicitExpressionParens()
{
ParseBlockTest("Html.Repeat(10," + TestNestedTemplateCode + ")",
new ExpressionBlock(
Factory.Code("Html.Repeat(10,").AsImplicitExpression(KeywordSet),
TestNestedTemplate(),
Factory.Code(")").AsImplicitExpression(KeywordSet).Accepts(AcceptedCharacters.NonWhiteSpace)),
GetNestedSectionError(41, 0, 41));
}
[Fact]
public void ParseBlockHandlesSimpleAnonymousSectionInStatementWithinCodeBlock()
{
ParseBlockTest("For Each foo in Bar " + Environment.NewLine
+ " Html.ExecuteTemplate(foo," + TestTemplateCode + ")" + Environment.NewLine
+ "Next foo",
new StatementBlock(
Factory.Code("For Each foo in Bar \r\n Html.ExecuteTemplate(foo,")
.AsStatement(),
TestTemplate(),
Factory.Code(")\r\nNext foo")
.AsStatement()
.Accepts(AcceptedCharacters.WhiteSpace | AcceptedCharacters.NonWhiteSpace)));
}
[Fact]
public void ParseBlockHandlesTwoAnonymousSectionsInStatementWithinCodeBlock()
{
ParseBlockTest("For Each foo in Bar " + Environment.NewLine
+ " Html.ExecuteTemplate(foo," + TestTemplateCode + "," + TestTemplateCode + ")" + Environment.NewLine
+ "Next foo",
new StatementBlock(
Factory.Code("For Each foo in Bar \r\n Html.ExecuteTemplate(foo,")
.AsStatement(),
TestTemplate(),
Factory.Code(",").AsStatement(),
TestTemplate(),
Factory.Code(")\r\nNext foo")
.AsStatement()
.Accepts(AcceptedCharacters.WhiteSpace | AcceptedCharacters.NonWhiteSpace)));
}
[Fact]
public void ParseBlockProducesErrorButCorrectlyParsesNestedAnonymousSectionInStatementWithinCodeBlock()
{
ParseBlockTest("For Each foo in Bar " + Environment.NewLine
+ " Html.ExecuteTemplate(foo," + TestNestedTemplateCode + ")" + Environment.NewLine
+ "Next foo",
new StatementBlock(
Factory.Code("For Each foo in Bar \r\n Html.ExecuteTemplate(foo,")
.AsStatement(),
TestNestedTemplate(),
Factory.Code(")\r\nNext foo")
.AsStatement()
.Accepts(AcceptedCharacters.WhiteSpace | AcceptedCharacters.NonWhiteSpace)),
GetNestedSectionError(77, 1, 55));
}
[Fact]
public void ParseBlockHandlesSimpleAnonymousSectionInStatementWithinStatementBlock()
{
ParseBlockTest("Code " + Environment.NewLine
+ " Dim foo = bar" + Environment.NewLine
+ " Html.ExecuteTemplate(foo," + TestTemplateCode + ")" + Environment.NewLine
+ "End Code",
new StatementBlock(
Factory.MetaCode("Code").Accepts(AcceptedCharacters.None),
Factory.Code(" \r\n Dim foo = bar\r\n Html.ExecuteTemplate(foo,")
.AsStatement(),
TestTemplate(),
Factory.Code(")\r\n").AsStatement(),
Factory.MetaCode("End Code").Accepts(AcceptedCharacters.None)));
}
[Fact]
public void ParseBlockHandlessTwoAnonymousSectionsInStatementWithinStatementBlock()
{
ParseBlockTest("Code" + Environment.NewLine
+ " Dim foo = bar" + Environment.NewLine
+ " Html.ExecuteTemplate(foo," + TestTemplateCode + "," + TestTemplateCode + ")" + Environment.NewLine
+ "End Code",
new StatementBlock(
Factory.MetaCode("Code").Accepts(AcceptedCharacters.None),
Factory.Code("\r\n Dim foo = bar\r\n Html.ExecuteTemplate(foo,")
.AsStatement(),
TestTemplate(),
Factory.Code(",").AsStatement(),
TestTemplate(),
Factory.Code(")\r\n").AsStatement(),
Factory.MetaCode("End Code").Accepts(AcceptedCharacters.None)));
}
[Fact]
public void ParseBlockProducesErrorButCorrectlyParsesNestedAnonymousSectionInStatementWithinStatementBlock()
{
ParseBlockTest("Code" + Environment.NewLine
+ " Dim foo = bar" + Environment.NewLine
+ " Html.ExecuteTemplate(foo," + TestNestedTemplateCode + ")" + Environment.NewLine
+ "End Code",
new StatementBlock(
Factory.MetaCode("Code").Accepts(AcceptedCharacters.None),
Factory.Code("\r\n Dim foo = bar\r\n Html.ExecuteTemplate(foo,")
.AsStatement(),
TestNestedTemplate(),
Factory.Code(")\r\n").AsStatement(),
Factory.MetaCode("End Code").Accepts(AcceptedCharacters.None)),
GetNestedSectionError(80, 2, 55));
}
private static RazorError GetNestedSectionError(int absoluteIndex, int lineIndex, int characterIndex)
{
return new RazorError(
RazorResources.ParseError_InlineMarkup_Blocks_Cannot_Be_Nested,
absoluteIndex, lineIndex, characterIndex);
}
}
}

View File

@ -0,0 +1,105 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.Razor.Editor;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.AspNet.Razor.Tokenizer.Symbols;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.Razor.Test.Parser.VB
{
public class VBToMarkupSwitchTest : VBHtmlCodeParserTestBase
{
[Fact]
public void ParseBlockSwitchesToMarkupWhenAtSignFollowedByLessThanInStatementBlock()
{
ParseBlockTest("Code" + Environment.NewLine
+ " If True Then" + Environment.NewLine
+ " @<p>It's True!</p>" + Environment.NewLine
+ " End If" + Environment.NewLine
+ "End Code",
new StatementBlock(
Factory.MetaCode("Code").Accepts(AcceptedCharacters.None),
Factory.Code("\r\n If True Then\r\n").AsStatement(),
new MarkupBlock(
Factory.Markup(" "),
Factory.MarkupTransition(),
Factory.Markup("<p>It's True!</p>\r\n").Accepts(AcceptedCharacters.None)),
Factory.Code(" End If\r\n").AsStatement(),
Factory.MetaCode("End Code").Accepts(AcceptedCharacters.None)));
}
[Fact]
public void ParseBlockGivesWhiteSpacePreceedingMarkupBlockToCodeInDesignTimeMode()
{
ParseBlockTest("Code" + Environment.NewLine
+ " @<p>Foo</p>" + Environment.NewLine
+ "End Code",
new StatementBlock(
Factory.MetaCode("Code").Accepts(AcceptedCharacters.None),
Factory.Code("\r\n ").AsStatement(),
new MarkupBlock(
Factory.MarkupTransition(),
Factory.Markup("<p>Foo</p>").Accepts(AcceptedCharacters.None)),
Factory.Code("\r\n").AsStatement(),
Factory.MetaCode("End Code").Accepts(AcceptedCharacters.None)),
designTimeParser: true);
}
[Theory]
[InlineData("While", "End While", AcceptedCharacters.None)]
[InlineData("If", "End If", AcceptedCharacters.None)]
[InlineData("Select", "End Select", AcceptedCharacters.None)]
[InlineData("For", "Next", AcceptedCharacters.WhiteSpace | AcceptedCharacters.NonWhiteSpace)]
[InlineData("Try", "End Try", AcceptedCharacters.None)]
[InlineData("With", "End With", AcceptedCharacters.None)]
[InlineData("Using", "End Using", AcceptedCharacters.None)]
public void SimpleMarkupSwitch(string keyword, string endSequence, AcceptedCharacters acceptedCharacters)
{
ParseBlockTest(keyword + Environment.NewLine
+ " If True Then" + Environment.NewLine
+ " @<p>It's True!</p>" + Environment.NewLine
+ " End If" + Environment.NewLine
+ endSequence,
new StatementBlock(
Factory.Code(keyword + "\r\n If True Then\r\n").AsStatement(),
new MarkupBlock(
Factory.Markup(" "),
Factory.MarkupTransition(),
Factory.Markup("<p>It's True!</p>\r\n").Accepts(AcceptedCharacters.None)),
Factory.Code(" End If\r\n" + endSequence).AsStatement().Accepts(acceptedCharacters)));
}
[Theory]
[InlineData("While", "End While", AcceptedCharacters.None)]
[InlineData("If", "End If", AcceptedCharacters.None)]
[InlineData("Select", "End Select", AcceptedCharacters.None)]
[InlineData("For", "Next", AcceptedCharacters.WhiteSpace | AcceptedCharacters.NonWhiteSpace)]
[InlineData("Try", "End Try", AcceptedCharacters.None)]
[InlineData("With", "End With", AcceptedCharacters.None)]
[InlineData("Using", "End Using", AcceptedCharacters.None)]
public void SingleLineMarkupSwitch(string keyword, string endSequence, AcceptedCharacters acceptedCharacters)
{
ParseBlockTest(keyword + Environment.NewLine
+ " If True Then" + Environment.NewLine
+ " @:<p>It's True!</p>" + Environment.NewLine
+ " This is code!" + Environment.NewLine
+ " End If" + Environment.NewLine
+ endSequence,
new StatementBlock(
Factory.Code(keyword + "\r\n If True Then\r\n").AsStatement(),
new MarkupBlock(
Factory.Markup(" "),
Factory.MarkupTransition(),
Factory.MetaMarkup(":", HtmlSymbolType.Colon),
Factory.Markup("<p>It's True!</p>\r\n")
.With(new SingleLineMarkupEditHandler(CSharpLanguageCharacteristics.Instance.TokenizeString))
.Accepts(AcceptedCharacters.None)),
Factory.Code(" This is code!\r\n End If\r\n" + endSequence)
.AsStatement()
.Accepts(acceptedCharacters)));
}
}
}

View File

@ -0,0 +1,51 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.Test.Framework;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.Razor.Test.Parser
{
public class WhitespaceRewriterTest
{
[Fact]
public void Constructor_Requires_NonNull_SymbolConverter()
{
Assert.ThrowsArgumentNull(() => new WhiteSpaceRewriter(null), "markupSpanFactory");
}
[Fact]
public void Rewrite_Moves_Whitespace_Preceeding_ExpressionBlock_To_Parent_Block()
{
// Arrange
var factory = SpanFactory.CreateCsHtml();
Block start = new MarkupBlock(
factory.Markup("test"),
new ExpressionBlock(
factory.Code(" ").AsExpression(),
factory.CodeTransition(SyntaxConstants.TransitionString),
factory.Code("foo").AsExpression()
),
factory.Markup("test")
);
WhiteSpaceRewriter rewriter = new WhiteSpaceRewriter(new HtmlMarkupParser().BuildSpan);
// Act
Block actual = rewriter.Rewrite(start);
factory.Reset();
// Assert
ParserTestBase.EvaluateParseTree(actual, new MarkupBlock(
factory.Markup("test"),
factory.Markup(" "),
new ExpressionBlock(
factory.CodeTransition(SyntaxConstants.TransitionString),
factory.Code("foo").AsExpression()
),
factory.Markup("test")
));
}
}
}

View File

@ -0,0 +1,49 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using Microsoft.TestCommon;
namespace Microsoft.AspNet.Razor.Test
{
public class RazorCodeLanguageTest
{
[Fact]
public void ServicesPropertyContainsEntriesForCSharpCodeLanguageService()
{
// Assert
Assert.Equal(2, RazorCodeLanguage.Languages.Count);
Assert.IsType<CSharpRazorCodeLanguage>(RazorCodeLanguage.Languages["cshtml"]);
Assert.IsType<VBRazorCodeLanguage>(RazorCodeLanguage.Languages["vbhtml"]);
}
[Fact]
public void GetServiceByExtensionReturnsEntryMatchingExtensionWithoutPreceedingDot()
{
Assert.IsType<CSharpRazorCodeLanguage>(RazorCodeLanguage.GetLanguageByExtension("cshtml"));
}
[Fact]
public void GetServiceByExtensionReturnsEntryMatchingExtensionWithPreceedingDot()
{
Assert.IsType<CSharpRazorCodeLanguage>(RazorCodeLanguage.GetLanguageByExtension(".cshtml"));
}
[Fact]
public void GetServiceByExtensionReturnsNullIfNoServiceForSpecifiedExtension()
{
Assert.Null(RazorCodeLanguage.GetLanguageByExtension("foobar"));
}
[Fact]
public void MultipleCallsToGetServiceWithSameExtensionReturnSameObject()
{
// Arrange
RazorCodeLanguage expected = RazorCodeLanguage.GetLanguageByExtension("cshtml");
// Act
RazorCodeLanguage actual = RazorCodeLanguage.GetLanguageByExtension("cshtml");
// Assert
Assert.Same(expected, actual);
}
}
}

View File

@ -0,0 +1,81 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.Linq;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.Razor.Test
{
public class RazorDirectiveAttributeTest
{
[Fact]
public void ConstructorThrowsIfNameIsNullOrEmpty()
{
// Act and Assert
Assert.ThrowsArgumentNullOrEmptyString(() => new RazorDirectiveAttribute(name: null, value: "blah"), "name");
Assert.ThrowsArgumentNullOrEmptyString(() => new RazorDirectiveAttribute(name: "", value: "blah"), "name");
}
[Fact]
public void EnsureRazorDirectiveProperties()
{
// Arrange
var attribute = (AttributeUsageAttribute)typeof(RazorDirectiveAttribute).GetCustomAttributes(typeof(AttributeUsageAttribute), inherit: false)
.SingleOrDefault();
// Assert
Assert.True(attribute.AllowMultiple);
Assert.True(attribute.ValidOn == AttributeTargets.Class);
Assert.True(attribute.Inherited);
}
[Fact]
public void EqualsAndGetHashCodeIgnoresCase()
{
// Arrange
var attribute1 = new RazorDirectiveAttribute("foo", "bar");
var attribute2 = new RazorDirectiveAttribute("fOo", "BAr");
// Act
var hashCode1 = attribute1.GetHashCode();
var hashCode2 = attribute2.GetHashCode();
// Assert
Assert.Equal(attribute1, attribute2);
Assert.Equal(hashCode1, hashCode2);
}
[Fact]
public void EqualsAndGetHashCodeDoNotThrowIfValueIsNullOrEmpty()
{
// Arrange
var attribute1 = new RazorDirectiveAttribute("foo", null);
var attribute2 = new RazorDirectiveAttribute("foo", "BAr");
// Act
bool result = attribute1.Equals(attribute2);
var hashCode = attribute1.GetHashCode();
// Assert
Assert.False(result);
// If we've got this far, GetHashCode did not throw
}
[Fact]
public void EqualsAndGetHashCodeReturnDifferentValuesForNullAndEmpty()
{
// Arrange
var attribute1 = new RazorDirectiveAttribute("foo", null);
var attribute2 = new RazorDirectiveAttribute("foo", "");
// Act
bool result = attribute1.Equals(attribute2);
var hashCode1 = attribute1.GetHashCode();
var hashCode2 = attribute2.GetHashCode();
// Assert
Assert.False(result);
Assert.NotEqual(hashCode1, hashCode2);
}
}
}

View File

@ -0,0 +1,187 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System.CodeDom;
using Microsoft.AspNet.Razor.Generator;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.TestCommon;
namespace Microsoft.AspNet.Razor.Test
{
public class RazorEngineHostTest
{
[Fact]
public void ConstructorRequiresNonNullCodeLanguage()
{
Assert.ThrowsArgumentNull(() => new RazorEngineHost(null), "codeLanguage");
Assert.ThrowsArgumentNull(() => new RazorEngineHost(null, () => new HtmlMarkupParser()), "codeLanguage");
}
[Fact]
public void ConstructorRequiresNonNullMarkupParser()
{
Assert.ThrowsArgumentNull(() => new RazorEngineHost(new CSharpRazorCodeLanguage(), null), "markupParserFactory");
}
[Fact]
public void ConstructorWithCodeLanguageSetsPropertiesAppropriately()
{
// Arrange
RazorCodeLanguage language = new CSharpRazorCodeLanguage();
// Act
RazorEngineHost host = new RazorEngineHost(language);
// Assert
VerifyCommonDefaults(host);
Assert.Same(language, host.CodeLanguage);
Assert.IsType<HtmlMarkupParser>(host.CreateMarkupParser());
}
[Fact]
public void ConstructorWithCodeLanguageAndMarkupParserSetsPropertiesAppropriately()
{
// Arrange
RazorCodeLanguage language = new CSharpRazorCodeLanguage();
ParserBase expected = new HtmlMarkupParser();
// Act
RazorEngineHost host = new RazorEngineHost(language, () => expected);
// Assert
VerifyCommonDefaults(host);
Assert.Same(language, host.CodeLanguage);
Assert.Same(expected, host.CreateMarkupParser());
}
[Fact]
public void DecorateCodeParserRequiresNonNullCodeParser()
{
Assert.ThrowsArgumentNull(() => CreateHost().DecorateCodeParser(null), "incomingCodeParser");
}
[Fact]
public void DecorateMarkupParserRequiresNonNullMarkupParser()
{
Assert.ThrowsArgumentNull(() => CreateHost().DecorateMarkupParser(null), "incomingMarkupParser");
}
[Fact]
public void DecorateCodeGeneratorRequiresNonNullCodeGenerator()
{
Assert.ThrowsArgumentNull(() => CreateHost().DecorateCodeGenerator(null), "incomingCodeGenerator");
}
[Fact]
public void PostProcessGeneratedCodeRequiresNonNullCompileUnit()
{
Assert.ThrowsArgumentNull(() => CreateHost().PostProcessGeneratedCode(codeCompileUnit: null,
generatedNamespace: new CodeNamespace(),
generatedClass: new CodeTypeDeclaration(),
executeMethod: new CodeMemberMethod()),
"codeCompileUnit");
}
[Fact]
public void PostProcessGeneratedCodeRequiresNonNullGeneratedNamespace()
{
Assert.ThrowsArgumentNull(() => CreateHost().PostProcessGeneratedCode(codeCompileUnit: new CodeCompileUnit(),
generatedNamespace: null,
generatedClass: new CodeTypeDeclaration(),
executeMethod: new CodeMemberMethod()),
"generatedNamespace");
}
[Fact]
public void PostProcessGeneratedCodeRequiresNonNullGeneratedClass()
{
Assert.ThrowsArgumentNull(() => CreateHost().PostProcessGeneratedCode(codeCompileUnit: new CodeCompileUnit(),
generatedNamespace: new CodeNamespace(),
generatedClass: null,
executeMethod: new CodeMemberMethod()),
"generatedClass");
}
[Fact]
public void PostProcessGeneratedCodeRequiresNonNullExecuteMethod()
{
Assert.ThrowsArgumentNull(() => CreateHost().PostProcessGeneratedCode(codeCompileUnit: new CodeCompileUnit(),
generatedNamespace: new CodeNamespace(),
generatedClass: new CodeTypeDeclaration(),
executeMethod: null),
"executeMethod");
}
[Fact]
public void DecorateCodeParserDoesNotModifyIncomingParser()
{
// Arrange
ParserBase expected = new CSharpCodeParser();
// Act
ParserBase actual = CreateHost().DecorateCodeParser(expected);
// Assert
Assert.Same(expected, actual);
}
[Fact]
public void DecorateMarkupParserReturnsIncomingParser()
{
// Arrange
ParserBase expected = new HtmlMarkupParser();
// Act
ParserBase actual = CreateHost().DecorateMarkupParser(expected);
// Assert
Assert.Same(expected, actual);
}
[Fact]
public void DecorateCodeGeneratorReturnsIncomingCodeGenerator()
{
// Arrange
RazorCodeGenerator expected = new CSharpRazorCodeGenerator("Foo", "Bar", "Baz", CreateHost());
// Act
RazorCodeGenerator actual = CreateHost().DecorateCodeGenerator(expected);
// Assert
Assert.Same(expected, actual);
}
[Fact]
public void PostProcessGeneratedCodeDoesNotModifyCode()
{
// Arrange
CodeCompileUnit compileUnit = new CodeCompileUnit();
CodeNamespace ns = new CodeNamespace();
CodeTypeDeclaration typeDecl = new CodeTypeDeclaration();
CodeMemberMethod execMethod = new CodeMemberMethod();
// Act
CreateHost().PostProcessGeneratedCode(compileUnit, ns, typeDecl, execMethod);
// Assert
Assert.Empty(compileUnit.Namespaces);
Assert.Empty(ns.Imports);
Assert.Empty(ns.Types);
Assert.Empty(typeDecl.Members);
Assert.Empty(execMethod.Statements);
}
private static RazorEngineHost CreateHost()
{
return new RazorEngineHost(new CSharpRazorCodeLanguage());
}
private static void VerifyCommonDefaults(RazorEngineHost host)
{
Assert.Equal(GeneratedClassContext.Default, host.GeneratedClassContext);
Assert.Empty(host.NamespaceImports);
Assert.False(host.DesignTimeMode);
Assert.Equal(RazorEngineHost.InternalDefaultClassName, host.DefaultClassName);
Assert.Equal(RazorEngineHost.InternalDefaultNamespace, host.DefaultNamespace);
}
}
}

View File

@ -0,0 +1,198 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System.IO;
using System.Threading;
using Microsoft.AspNet.Razor.Generator;
using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.Text;
using System.Web.WebPages.TestUtils;
using Microsoft.TestCommon;
using Moq;
namespace Microsoft.AspNet.Razor.Test
{
public class RazorTemplateEngineTest
{
[Fact]
public void ConstructorRequiresNonNullHost()
{
Assert.ThrowsArgumentNull(() => new RazorTemplateEngine(null), "host");
}
[Fact]
public void ConstructorInitializesHost()
{
// Arrange
RazorEngineHost host = new RazorEngineHost(new CSharpRazorCodeLanguage());
// Act
RazorTemplateEngine engine = new RazorTemplateEngine(host);
// Assert
Assert.Same(host, engine.Host);
}
[Fact]
public void CreateParserMethodIsConstructedFromHost()
{
// Arrange
RazorEngineHost host = CreateHost();
RazorTemplateEngine engine = new RazorTemplateEngine(host);
// Act
RazorParser parser = engine.CreateParser();
// Assert
Assert.IsType<CSharpCodeParser>(parser.CodeParser);
Assert.IsType<HtmlMarkupParser>(parser.MarkupParser);
}
[Fact]
public void CreateParserMethodSetsParserContextToDesignTimeModeIfHostSetToDesignTimeMode()
{
// Arrange
RazorEngineHost host = CreateHost();
RazorTemplateEngine engine = new RazorTemplateEngine(host);
host.DesignTimeMode = true;
// Act
RazorParser parser = engine.CreateParser();
// Assert
Assert.True(parser.DesignTimeMode);
}
[Fact]
public void CreateParserMethodPassesParsersThroughDecoratorMethodsOnHost()
{
// Arrange
ParserBase expectedCode = new Mock<ParserBase>().Object;
ParserBase expectedMarkup = new Mock<ParserBase>().Object;
var mockHost = new Mock<RazorEngineHost>(new CSharpRazorCodeLanguage()) { CallBase = true };
mockHost.Setup(h => h.DecorateCodeParser(It.IsAny<CSharpCodeParser>()))
.Returns(expectedCode);
mockHost.Setup(h => h.DecorateMarkupParser(It.IsAny<HtmlMarkupParser>()))
.Returns(expectedMarkup);
RazorTemplateEngine engine = new RazorTemplateEngine(mockHost.Object);
// Act
RazorParser actual = engine.CreateParser();
// Assert
Assert.Equal(expectedCode, actual.CodeParser);
Assert.Equal(expectedMarkup, actual.MarkupParser);
}
[Fact]
public void CreateCodeGeneratorMethodPassesCodeGeneratorThroughDecorateMethodOnHost()
{
// Arrange
var mockHost = new Mock<RazorEngineHost>(new CSharpRazorCodeLanguage()) { CallBase = true };
RazorCodeGenerator expected = new Mock<RazorCodeGenerator>("Foo", "Bar", "Baz", mockHost.Object).Object;
mockHost.Setup(h => h.DecorateCodeGenerator(It.IsAny<CSharpRazorCodeGenerator>()))
.Returns(expected);
RazorTemplateEngine engine = new RazorTemplateEngine(mockHost.Object);
// Act
RazorCodeGenerator actual = engine.CreateCodeGenerator("Foo", "Bar", "Baz");
// Assert
Assert.Equal(expected, actual);
}
[Fact]
public void ParseTemplateCopiesTextReaderContentToSeekableTextReaderAndPassesToParseTemplateCore()
{
// Arrange
Mock<RazorTemplateEngine> mockEngine = new Mock<RazorTemplateEngine>(CreateHost());
TextReader reader = new StringReader("foo");
CancellationTokenSource source = new CancellationTokenSource();
// Act
mockEngine.Object.ParseTemplate(reader, cancelToken: source.Token);
// Assert
mockEngine.Verify(e => e.ParseTemplateCore(It.Is<SeekableTextReader>(l => l.ReadToEnd() == "foo"),
source.Token));
}
[Fact]
public void GenerateCodeCopiesTextReaderContentToSeekableTextReaderAndPassesToGenerateCodeCore()
{
// Arrange
Mock<RazorTemplateEngine> mockEngine = new Mock<RazorTemplateEngine>(CreateHost());
TextReader reader = new StringReader("foo");
CancellationTokenSource source = new CancellationTokenSource();
string className = "Foo";
string ns = "Bar";
string src = "Baz";
// Act
mockEngine.Object.GenerateCode(reader, className: className, rootNamespace: ns, sourceFileName: src, cancelToken: source.Token);
// Assert
mockEngine.Verify(e => e.GenerateCodeCore(It.Is<SeekableTextReader>(l => l.ReadToEnd() == "foo"),
className, ns, src, source.Token));
}
[Fact]
public void ParseTemplateOutputsResultsOfParsingProvidedTemplateSource()
{
// Arrange
RazorTemplateEngine engine = new RazorTemplateEngine(CreateHost());
// Act
ParserResults results = engine.ParseTemplate(new StringTextBuffer("foo @bar("));
// Assert
Assert.False(results.Success);
Assert.Single(results.ParserErrors);
Assert.NotNull(results.Document);
}
[Fact]
public void GenerateOutputsResultsOfParsingAndGeneration()
{
// Arrange
RazorTemplateEngine engine = new RazorTemplateEngine(CreateHost());
// Act
GeneratorResults results = engine.GenerateCode(new StringTextBuffer("foo @bar("));
// Assert
Assert.False(results.Success);
Assert.Single(results.ParserErrors);
Assert.NotNull(results.Document);
Assert.NotNull(results.GeneratedCode);
Assert.Null(results.DesignTimeLineMappings);
}
[Fact]
public void GenerateOutputsDesignTimeMappingsIfDesignTimeSetOnHost()
{
// Arrange
RazorTemplateEngine engine = new RazorTemplateEngine(CreateHost(designTime: true));
// Act
GeneratorResults results = engine.GenerateCode(new StringTextBuffer("foo @bar()"), className: null, rootNamespace: null, sourceFileName: "foo.cshtml");
// Assert
Assert.True(results.Success);
Assert.Empty(results.ParserErrors);
Assert.NotNull(results.Document);
Assert.NotNull(results.GeneratedCode);
Assert.NotNull(results.DesignTimeLineMappings);
}
private static RazorEngineHost CreateHost(bool designTime = false)
{
return new RazorEngineHost(new CSharpRazorCodeLanguage())
{
DesignTimeMode = designTime
};
}
}
}

View File

@ -0,0 +1,52 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using Microsoft.AspNet.Razor.Text;
namespace System.Web.WebPages.TestUtils
{
public class StringTextBuffer : ITextBuffer, IDisposable
{
private string _buffer;
public bool Disposed { get; set; }
public StringTextBuffer(string buffer)
{
_buffer = buffer;
}
public int Length
{
get { return _buffer.Length; }
}
public int Position { get; set; }
public int Read()
{
if (Position >= _buffer.Length)
{
return -1;
}
return _buffer[Position++];
}
public int Peek()
{
if (Position >= _buffer.Length)
{
return -1;
}
return _buffer[Position];
}
public void Dispose()
{
Disposed = true;
}
public object VersionToken
{
get { return _buffer; }
}
}
}

View File

@ -0,0 +1,194 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:N.N.NNNNN.N
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace TestOutput {
using System;
public class Blocks {
#line hidden
public Blocks() {
}
public override void Execute() {
#line 1 "Blocks.cshtml"
int i = 1;
#line default
#line hidden
WriteLiteral("\r\n\r\n");
#line 5 "Blocks.cshtml"
while(i <= 10) {
#line default
#line hidden
WriteLiteral(" <p>Hello from C#, #");
#line 6 "Blocks.cshtml"
Write(i);
#line default
#line hidden
WriteLiteral("</p>\r\n");
#line 7 "Blocks.cshtml"
i += 1;
}
#line default
#line hidden
WriteLiteral("\r\n");
#line 10 "Blocks.cshtml"
if(i == 11) {
#line default
#line hidden
WriteLiteral(" <p>We wrote 10 lines!</p>\r\n");
#line 12 "Blocks.cshtml"
}
#line default
#line hidden
WriteLiteral("\r\n");
#line 14 "Blocks.cshtml"
switch(i) {
case 11:
#line default
#line hidden
WriteLiteral(" <p>No really, we wrote 10 lines!</p>\r\n");
#line 17 "Blocks.cshtml"
break;
default:
#line default
#line hidden
WriteLiteral(" <p>Actually, we didn\'t...</p>\r\n");
#line 20 "Blocks.cshtml"
break;
}
#line default
#line hidden
WriteLiteral("\r\n");
#line 23 "Blocks.cshtml"
for(int j = 1; j <= 10; j += 2) {
#line default
#line hidden
WriteLiteral(" <p>Hello again from C#, #");
#line 24 "Blocks.cshtml"
Write(j);
#line default
#line hidden
WriteLiteral("</p>\r\n");
#line 25 "Blocks.cshtml"
}
#line default
#line hidden
WriteLiteral("\r\n");
#line 27 "Blocks.cshtml"
try {
#line default
#line hidden
WriteLiteral(" <p>That time, we wrote 5 lines!</p>\r\n");
#line 29 "Blocks.cshtml"
} catch(Exception ex) {
#line default
#line hidden
WriteLiteral(" <p>Oh no! An error occurred: ");
#line 30 "Blocks.cshtml"
Write(ex.Message);
#line default
#line hidden
WriteLiteral("</p>\r\n");
#line 31 "Blocks.cshtml"
}
#line default
#line hidden
WriteLiteral("\r\n<p>i is now ");
#line 33 "Blocks.cshtml"
Write(i);
#line default
#line hidden
WriteLiteral("</p>\r\n\r\n");
#line 35 "Blocks.cshtml"
lock(new object()) {
#line default
#line hidden
WriteLiteral(" <p>This block is locked, for your security!</p>\r\n");
#line 37 "Blocks.cshtml"
}
#line default
#line hidden
}
}
}

View File

@ -0,0 +1,31 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:N.N.NNNNN.N
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace TestOutput {
using System;
public class CodeBlock {
#line hidden
public CodeBlock() {
}
public override void Execute() {
#line 1 "CodeBlock.cshtml"
for(int i = 1; i <= 10; i++) {
Output.Write("<p>Hello from C#, #" + i.ToString() + "</p>");
}
#line default
#line hidden
}
}
}

View File

@ -0,0 +1,27 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:N.N.NNNNN.N
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace TestOutput {
using System;
public class CodeBlockAtEOF {
#line hidden
public CodeBlockAtEOF() {
}
public override void Execute() {
#line 1 "CodeBlockAtEOF.cshtml"
#line default
#line hidden
}
}
}

View File

@ -0,0 +1,38 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:N.N.NNNNN.N
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace TestOutput {
using System;
public class Comments {
public override void Execute() {
#line 1 "Comments.cshtml"
//This is not going to be rendered
#line default
#line hidden
WriteLiteral("<p>This is going to be rendered</p>\r\n");
#line 3 "Comments.cshtml"
/* Neither is this
nor this
nor this */
#line default
#line hidden
}
}
}

View File

@ -0,0 +1,197 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:N.N.NNNNN.N
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace TestOutput {
using System;
public class ConditionalAttributes {
#line hidden
public ConditionalAttributes() {
}
public override void Execute() {
#line 1 "ConditionalAttributes.cshtml"
var ch = true;
var cls = "bar";
#line default
#line hidden
WriteLiteral(" <a");
WriteLiteral(" href=\"Foo\"");
WriteLiteral(" />\r\n");
WriteLiteral(" <p");
WriteAttribute("class", Tuple.Create(" class=\"", 74), Tuple.Create("\"", 86)
#line 5 "ConditionalAttributes.cshtml"
, Tuple.Create(Tuple.Create("", 82), Tuple.Create<System.Object, System.Int32>(cls
#line default
#line hidden
, 82), false)
);
WriteLiteral(" />\r\n");
WriteLiteral(" <p");
WriteAttribute("class", Tuple.Create(" class=\"", 98), Tuple.Create("\"", 114)
, Tuple.Create(Tuple.Create("", 106), Tuple.Create("foo", 106), true)
#line 6 "ConditionalAttributes.cshtml"
, Tuple.Create(Tuple.Create(" ", 109), Tuple.Create<System.Object, System.Int32>(cls
#line default
#line hidden
, 110), false)
);
WriteLiteral(" />\r\n");
WriteLiteral(" <p");
WriteAttribute("class", Tuple.Create(" class=\"", 126), Tuple.Create("\"", 142)
#line 7 "ConditionalAttributes.cshtml"
, Tuple.Create(Tuple.Create("", 134), Tuple.Create<System.Object, System.Int32>(cls
#line default
#line hidden
, 134), false)
, Tuple.Create(Tuple.Create(" ", 138), Tuple.Create("foo", 139), true)
);
WriteLiteral(" />\r\n");
WriteLiteral(" <input");
WriteLiteral(" type=\"checkbox\"");
WriteAttribute("checked", Tuple.Create(" checked=\"", 174), Tuple.Create("\"", 187)
#line 8 "ConditionalAttributes.cshtml"
, Tuple.Create(Tuple.Create("", 184), Tuple.Create<System.Object, System.Int32>(ch
#line default
#line hidden
, 184), false)
);
WriteLiteral(" />\r\n");
WriteLiteral(" <input");
WriteLiteral(" type=\"checkbox\"");
WriteAttribute("checked", Tuple.Create(" checked=\"", 219), Tuple.Create("\"", 236)
, Tuple.Create(Tuple.Create("", 229), Tuple.Create("foo", 229), true)
#line 9 "ConditionalAttributes.cshtml"
, Tuple.Create(Tuple.Create(" ", 232), Tuple.Create<System.Object, System.Int32>(ch
#line default
#line hidden
, 233), false)
);
WriteLiteral(" />\r\n");
WriteLiteral(" <p");
WriteAttribute("class", Tuple.Create(" class=\"", 248), Tuple.Create("\"", 281)
, Tuple.Create(Tuple.Create("", 256), Tuple.Create<System.Object, System.Int32>(new Template(__razor_attribute_value_writer => {
#line 10 "ConditionalAttributes.cshtml"
if(cls != null) {
#line default
#line hidden
#line 10 "ConditionalAttributes.cshtml"
WriteTo(__razor_attribute_value_writer, cls);
#line default
#line hidden
#line 10 "ConditionalAttributes.cshtml"
}
#line default
#line hidden
}), 256), false)
);
WriteLiteral(" />\r\n");
WriteLiteral(" <a");
WriteAttribute("href", Tuple.Create(" href=\"", 293), Tuple.Create("\"", 305)
, Tuple.Create(Tuple.Create("", 300), Tuple.Create<System.Object, System.Int32>(Href("~/Foo")
, 300), false)
);
WriteLiteral(" />\r\n");
WriteLiteral(" <script");
WriteAttribute("src", Tuple.Create(" src=\"", 322), Tuple.Create("\"", 373)
#line 12 "ConditionalAttributes.cshtml"
, Tuple.Create(Tuple.Create("", 328), Tuple.Create<System.Object, System.Int32>(Url.Content("~/Scripts/jquery-1.6.2.min.js")
#line default
#line hidden
, 328), false)
);
WriteLiteral(" type=\"text/javascript\"");
WriteLiteral("></script>\r\n");
WriteLiteral(" <script");
WriteAttribute("src", Tuple.Create(" src=\"", 420), Tuple.Create("\"", 487)
#line 13 "ConditionalAttributes.cshtml"
, Tuple.Create(Tuple.Create("", 426), Tuple.Create<System.Object, System.Int32>(Url.Content("~/Scripts/modernizr-2.0.6-development-only.js")
#line default
#line hidden
, 426), false)
);
WriteLiteral(" type=\"text/javascript\"");
WriteLiteral("></script>\r\n");
WriteLiteral(" <script");
WriteLiteral(" src=\"http://ajax.aspnetcdn.com/ajax/jquery.ui/1.8.16/jquery-ui.min.js\"");
WriteLiteral(" type=\"text/javascript\"");
WriteLiteral("></script>\r\n");
#line 15 "ConditionalAttributes.cshtml"
#line default
#line hidden
}
}
}

View File

@ -0,0 +1,110 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:N.N.NNNNN.N
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace TestOutput {
using System;
public class DesignTime {
private static object @__o;
#line hidden
#line 9 "DesignTime.cshtml"
public static Template Foo() {
#line default
#line hidden
return new Template(__razor_helper_writer => {
#line 10 "DesignTime.cshtml"
if(true) {
#line default
#line hidden
#line 11 "DesignTime.cshtml"
}
#line default
#line hidden
});
#line 12 "DesignTime.cshtml"
}
#line default
#line hidden
public DesignTime() {
}
public override void Execute() {
#line 1 "DesignTime.cshtml"
for(int i = 1; i <= 10; i++) {
#line default
#line hidden
#line 2 "DesignTime.cshtml"
__o = i;
#line default
#line hidden
#line 3 "DesignTime.cshtml"
}
#line default
#line hidden
#line 4 "DesignTime.cshtml"
__o = Foo(Bar.Baz);
#line default
#line hidden
#line 5 "DesignTime.cshtml"
__o = Foo(item => new Template(__razor_template_writer => {
#line default
#line hidden
#line 6 "DesignTime.cshtml"
__o = baz;
#line default
#line hidden
#line 7 "DesignTime.cshtml"
}));
#line default
#line hidden
DefineSection("Footer", () => {
#line 8 "DesignTime.cshtml"
__o = bar;
#line default
#line hidden
});
}
}
}

View File

@ -0,0 +1,110 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:N.N.NNNNN.N
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace TestOutput {
using System;
public class DesignTime {
private static object @__o;
#line hidden
#line 9 "DesignTime.cshtml"
public static Template Foo() {
#line default
#line hidden
return new Template(__razor_helper_writer => {
#line 10 "DesignTime.cshtml"
if(true) {
#line default
#line hidden
#line 11 "DesignTime.cshtml"
}
#line default
#line hidden
});
#line 12 "DesignTime.cshtml"
}
#line default
#line hidden
public DesignTime() {
}
public override void Execute() {
#line 1 "DesignTime.cshtml"
for(int i = 1; i <= 10; i++) {
#line default
#line hidden
#line 2 "DesignTime.cshtml"
__o = i;
#line default
#line hidden
#line 3 "DesignTime.cshtml"
}
#line default
#line hidden
#line 4 "DesignTime.cshtml"
__o = Foo(Bar.Baz);
#line default
#line hidden
#line 5 "DesignTime.cshtml"
__o = Foo(item => new Template(__razor_template_writer => {
#line default
#line hidden
#line 6 "DesignTime.cshtml"
__o = baz;
#line default
#line hidden
#line 7 "DesignTime.cshtml"
}));
#line default
#line hidden
DefineSection("Footer", () => {
#line 8 "DesignTime.cshtml"
__o = bar;
#line default
#line hidden
});
}
}
}

View File

@ -0,0 +1,27 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:N.N.NNNNN.N
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace TestOutput {
using System;
public class EmptyCodeBlock {
#line hidden
public EmptyCodeBlock() {
}
public override void Execute() {
#line 1 "EmptyCodeBlock.cshtml"
#line default
#line hidden
}
}
}

View File

@ -0,0 +1,29 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:N.N.NNNNN.N
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace TestOutput {
using System;
public class EmptyExplicitExpression {
private static object @__o;
#line hidden
public EmptyExplicitExpression() {
}
public override void Execute() {
#line 1 "EmptyExplicitExpression.cshtml"
__o = ;
#line default
#line hidden
}
}
}

View File

@ -0,0 +1,29 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:N.N.NNNNN.N
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace TestOutput {
using System;
public class EmptyImplicitExpression {
private static object @__o;
#line hidden
public EmptyImplicitExpression() {
}
public override void Execute() {
#line 1 "EmptyImplicitExpression.cshtml"
__o = ;
#line default
#line hidden
}
}
}

View File

@ -0,0 +1,43 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:N.N.NNNNN.N
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace TestOutput {
using System;
public class EmptyImplicitExpressionInCode {
private static object @__o;
#line hidden
public EmptyImplicitExpressionInCode() {
}
public override void Execute() {
#line 1 "EmptyImplicitExpressionInCode.cshtml"
#line default
#line hidden
#line 2 "EmptyImplicitExpressionInCode.cshtml"
__o = ;
#line default
#line hidden
#line 3 "EmptyImplicitExpressionInCode.cshtml"
#line default
#line hidden
}
}
}

View File

@ -0,0 +1,43 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:N.N.NNNNN.N
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace TestOutput {
using System;
public class EmptyImplicitExpressionInCode {
private static object @__o;
#line hidden
public EmptyImplicitExpressionInCode() {
}
public override void Execute() {
#line 1 "EmptyImplicitExpressionInCode.cshtml"
#line default
#line hidden
#line 2 "EmptyImplicitExpressionInCode.cshtml"
__o = ;
#line default
#line hidden
#line 3 "EmptyImplicitExpressionInCode.cshtml"
#line default
#line hidden
}
}
}

View File

@ -0,0 +1,30 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:N.N.NNNNN.N
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace TestOutput {
using System;
public class ExplicitExpression {
#line hidden
public ExplicitExpression() {
}
public override void Execute() {
WriteLiteral("1 + 1 = ");
#line 1 "ExplicitExpression.cshtml"
Write(1+1);
#line default
#line hidden
}
}
}

Some files were not shown because too many files have changed in this diff Show More