You've already forked linux-packaging-mono
acceptance-tests
data
docs
external
Newtonsoft.Json
api-doc-tools
api-snapshot
aspnetwebstack
packages
src
test
Microsoft.TestCommon
Microsoft.Web.Helpers.Test
Microsoft.Web.Http.Data.Test
Microsoft.Web.Mvc.Test
Microsoft.Web.WebPages.OAuth.Test
SPA.Test
System.Json.Test.Integration
System.Json.Test.Unit
System.Net.Http.Formatting.Test.Integration
System.Net.Http.Formatting.Test.Unit
System.Web.Helpers.Test
System.Web.Http.Integration.Test
System.Web.Http.SelfHost.Test
System.Web.Http.Test
System.Web.Http.WebHost.Test
System.Web.Mvc.Test
System.Web.Razor.Test
Editor
Framework
BlockExtensions.cs
BlockTypes.cs
CodeParserTestBase.cs
CsHtmlCodeParserTestBase.cs
CsHtmlMarkupParserTestBase.cs
ErrorCollector.cs
MarkupParserTestBase.cs
ParserTestBase.cs
RawTextSymbol.cs
TestSpanBuilder.cs
VBHtmlCodeParserTestBase.cs
VBHtmlMarkupParserTestBase.cs
Generator
Parser
Properties
TestFiles
Text
Tokenizer
Utils
CSharpRazorCodeLanguageTest.cs
CodeCompileUnitExtensions.cs
RazorCodeLanguageTest.cs
RazorDirectiveAttributeTest.cs
RazorEngineHostTest.cs
RazorTemplateEngineTest.cs
StringTextBuffer.cs
System.Web.Razor.Test.csproj
VBRazorCodeLanguageTest.cs
packages.config
System.Web.WebPages.Administration.Test
System.Web.WebPages.Deployment.Test
System.Web.WebPages.Razor.Test
System.Web.WebPages.Test
WebMatrix.Data.Test
WebMatrix.WebData.Test
Settings.StyleCop
tools
.gitattributes
.gitignore
License.txt
README.md
Runtime.msbuild
Runtime.sln
Runtime.xunit
Settings.StyleCop
build.cmd
bdwgc
binary-reference-assemblies
bockbuild
boringssl
cecil
cecil-legacy
corefx
corert
helix-binaries
ikdasm
ikvm
illinker-test-assets
linker
llvm-project
nuget-buildtasks
nunit-lite
roslyn-binaries
rx
xunit-binaries
how-to-bump-roslyn-binaries.md
ikvm-native
llvm
m4
man
mcs
mono
msvc
netcore
po
runtime
samples
scripts
support
tools
COPYING.LIB
LICENSE
Makefile.am
Makefile.in
NEWS
README.md
acinclude.m4
aclocal.m4
autogen.sh
code_of_conduct.md
compile
config.guess
config.h.in
config.rpath
config.sub
configure.REMOVED.git-id
configure.ac.REMOVED.git-id
depcomp
install-sh
ltmain.sh.REMOVED.git-id
missing
mkinstalldirs
mono-uninstalled.pc.in
test-driver
winconfig.h
384 lines
15 KiB
C#
384 lines
15 KiB
C#
// 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) { }
|
|
}
|
|
}
|
|
}
|