Imported Upstream version 3.6.0

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

View File

@ -0,0 +1,29 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Web.Razor.Parser.SyntaxTree;
namespace System.Web.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 Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Web.Razor.Generator;
using System.Web.Razor.Parser.SyntaxTree;
namespace System.Web.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 Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Web.Razor.Parser;
using System.Web.Razor.Parser.SyntaxTree;
namespace System.Web.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 Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Web.Razor.Parser;
namespace System.Web.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 Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Web.Razor.Parser;
namespace System.Web.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,56 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Text;
using System.Web.Razor.Utils;
namespace System.Web.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,71 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Web.Razor.Parser;
using System.Web.Razor.Parser.SyntaxTree;
namespace System.Web.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);
}
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);
}
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);
}
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);
}
}
}

View File

@ -0,0 +1,383 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
//#define PARSER_TRACE
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Web.Razor.Generator;
using System.Web.Razor.Parser;
using System.Web.Razor.Parser.SyntaxTree;
using System.Web.Razor.Text;
using Xunit;
namespace System.Web.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 ParserResults RunParse(string document, Func<ParserBase, Action> parserActionSelector, bool designTimeParser)
{
// 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(context.ActiveParser)();
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)
{
// Create the source
ParserResults results = RunParse(document, parserActionSelector, designTimeParser);
// 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,73 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Globalization;
using System.Web.Razor.Parser.SyntaxTree;
using System.Web.Razor.Text;
using System.Web.Razor.Tokenizer.Symbols;
using Microsoft.Internal.Web.Utils;
namespace System.Web.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,407 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Linq;
using System.Web.Razor.Editor;
using System.Web.Razor.Generator;
using System.Web.Razor.Parser;
using System.Web.Razor.Parser.SyntaxTree;
using System.Web.Razor.Text;
using System.Web.Razor.Tokenizer;
using System.Web.Razor.Tokenizer.Symbols;
namespace System.Web.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 Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Web.Razor.Parser;
namespace System.Web.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 Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Web.Razor.Parser;
namespace System.Web.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();
}
}
}