PageRenderTime 38ms CodeModel.GetById 8ms RepoModel.GetById 1ms app.codeStats 0ms

/test/System.Web.Razor.Test/Framework/ParserTestBase.cs

https://bitbucket.org/mdavid/aspnetwebstack
C# | 381 lines | 326 code | 47 blank | 8 comment | 34 complexity | 35e13fcac4e9fb26ed63e4e6b67dc559 MD5 | raw file
  1. //#define PARSER_TRACE
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.Linq;
  5. using System.Text;
  6. using System.Web.Razor.Generator;
  7. using System.Web.Razor.Parser;
  8. using System.Web.Razor.Parser.SyntaxTree;
  9. using System.Web.Razor.Text;
  10. using Xunit;
  11. namespace System.Web.Razor.Test.Framework
  12. {
  13. public abstract class ParserTestBase
  14. {
  15. protected static Block IgnoreOutput = new IgnoreOutputBlock();
  16. public SpanFactory Factory { get; private set; }
  17. protected ParserTestBase()
  18. {
  19. Factory = CreateSpanFactory();
  20. }
  21. public abstract ParserBase CreateMarkupParser();
  22. public abstract ParserBase CreateCodeParser();
  23. protected abstract ParserBase SelectActiveParser(ParserBase codeParser, ParserBase markupParser);
  24. public virtual ParserContext CreateParserContext(ITextDocument input, ParserBase codeParser, ParserBase markupParser)
  25. {
  26. return new ParserContext(input, codeParser, markupParser, SelectActiveParser(codeParser, markupParser));
  27. }
  28. protected abstract SpanFactory CreateSpanFactory();
  29. protected virtual void ParseBlockTest(string document)
  30. {
  31. ParseBlockTest(document, null, false, new RazorError[0]);
  32. }
  33. protected virtual void ParseBlockTest(string document, bool designTimeParser)
  34. {
  35. ParseBlockTest(document, null, designTimeParser, new RazorError[0]);
  36. }
  37. protected virtual void ParseBlockTest(string document, params RazorError[] expectedErrors)
  38. {
  39. ParseBlockTest(document, false, expectedErrors);
  40. }
  41. protected virtual void ParseBlockTest(string document, bool designTimeParser, params RazorError[] expectedErrors)
  42. {
  43. ParseBlockTest(document, null, designTimeParser, expectedErrors);
  44. }
  45. protected virtual void ParseBlockTest(string document, Block expectedRoot)
  46. {
  47. ParseBlockTest(document, expectedRoot, false, null);
  48. }
  49. protected virtual void ParseBlockTest(string document, Block expectedRoot, bool designTimeParser)
  50. {
  51. ParseBlockTest(document, expectedRoot, designTimeParser, null);
  52. }
  53. protected virtual void ParseBlockTest(string document, Block expectedRoot, params RazorError[] expectedErrors)
  54. {
  55. ParseBlockTest(document, expectedRoot, false, expectedErrors);
  56. }
  57. protected virtual void ParseBlockTest(string document, Block expectedRoot, bool designTimeParser, params RazorError[] expectedErrors)
  58. {
  59. RunParseTest(document, parser => parser.ParseBlock, expectedRoot, (expectedErrors ?? new RazorError[0]).ToList(), designTimeParser);
  60. }
  61. protected virtual void SingleSpanBlockTest(string document, BlockType blockType, SpanKind spanType, AcceptedCharacters acceptedCharacters = AcceptedCharacters.Any)
  62. {
  63. SingleSpanBlockTest(document, blockType, spanType, acceptedCharacters, expectedError: null);
  64. }
  65. protected virtual void SingleSpanBlockTest(string document, string spanContent, BlockType blockType, SpanKind spanType, AcceptedCharacters acceptedCharacters = AcceptedCharacters.Any)
  66. {
  67. SingleSpanBlockTest(document, spanContent, blockType, spanType, acceptedCharacters, expectedErrors: null);
  68. }
  69. protected virtual void SingleSpanBlockTest(string document, BlockType blockType, SpanKind spanType, params RazorError[] expectedError)
  70. {
  71. SingleSpanBlockTest(document, document, blockType, spanType, expectedError);
  72. }
  73. protected virtual void SingleSpanBlockTest(string document, string spanContent, BlockType blockType, SpanKind spanType, params RazorError[] expectedErrors)
  74. {
  75. SingleSpanBlockTest(document, spanContent, blockType, spanType, AcceptedCharacters.Any, expectedErrors ?? new RazorError[0]);
  76. }
  77. protected virtual void SingleSpanBlockTest(string document, BlockType blockType, SpanKind spanType, AcceptedCharacters acceptedCharacters, params RazorError[] expectedError)
  78. {
  79. SingleSpanBlockTest(document, document, blockType, spanType, acceptedCharacters, expectedError);
  80. }
  81. protected virtual void SingleSpanBlockTest(string document, string spanContent, BlockType blockType, SpanKind spanType, AcceptedCharacters acceptedCharacters, params RazorError[] expectedErrors)
  82. {
  83. BlockBuilder builder = new BlockBuilder();
  84. builder.Type = blockType;
  85. ParseBlockTest(
  86. document,
  87. ConfigureAndAddSpanToBlock(
  88. builder,
  89. Factory.Span(spanType, spanContent, spanType == SpanKind.Markup)
  90. .Accepts(acceptedCharacters)),
  91. expectedErrors ?? new RazorError[0]);
  92. }
  93. protected virtual ParserResults RunParse(string document, Func<ParserBase, Action> parserActionSelector, bool designTimeParser)
  94. {
  95. // Create the source
  96. ParserResults results = null;
  97. using (SeekableTextReader reader = new SeekableTextReader(document))
  98. {
  99. try
  100. {
  101. ParserBase codeParser = CreateCodeParser();
  102. ParserBase markupParser = CreateMarkupParser();
  103. ParserContext context = CreateParserContext(reader, codeParser, markupParser);
  104. context.DesignTimeMode = designTimeParser;
  105. codeParser.Context = context;
  106. markupParser.Context = context;
  107. // Run the parser
  108. parserActionSelector(context.ActiveParser)();
  109. results = context.CompleteParse();
  110. }
  111. finally
  112. {
  113. if (results != null && results.Document != null)
  114. {
  115. WriteTraceLine(String.Empty);
  116. WriteTraceLine("Actual Parse Tree:");
  117. WriteNode(0, results.Document);
  118. }
  119. }
  120. }
  121. return results;
  122. }
  123. protected virtual void RunParseTest(string document, Func<ParserBase, Action> parserActionSelector, Block expectedRoot, IList<RazorError> expectedErrors, bool designTimeParser)
  124. {
  125. // Create the source
  126. ParserResults results = RunParse(document, parserActionSelector, designTimeParser);
  127. // Evaluate the results
  128. if (!ReferenceEquals(expectedRoot, IgnoreOutput))
  129. {
  130. EvaluateResults(results, expectedRoot, expectedErrors);
  131. }
  132. }
  133. [Conditional("PARSER_TRACE")]
  134. private void WriteNode(int indent, SyntaxTreeNode node)
  135. {
  136. string content = node.ToString().Replace("\r", "\\r")
  137. .Replace("\n", "\\n")
  138. .Replace("{", "{{")
  139. .Replace("}", "}}");
  140. if (indent > 0)
  141. {
  142. content = new String('.', indent * 2) + content;
  143. }
  144. WriteTraceLine(content);
  145. Block block = node as Block;
  146. if (block != null)
  147. {
  148. foreach (SyntaxTreeNode child in block.Children)
  149. {
  150. WriteNode(indent + 1, child);
  151. }
  152. }
  153. }
  154. public static void EvaluateResults(ParserResults results, Block expectedRoot)
  155. {
  156. EvaluateResults(results, expectedRoot, null);
  157. }
  158. public static void EvaluateResults(ParserResults results, Block expectedRoot, IList<RazorError> expectedErrors)
  159. {
  160. EvaluateParseTree(results.Document, expectedRoot);
  161. EvaluateRazorErrors(results.ParserErrors, expectedErrors);
  162. }
  163. public static void EvaluateParseTree(Block actualRoot, Block expectedRoot)
  164. {
  165. // Evaluate the result
  166. ErrorCollector collector = new ErrorCollector();
  167. // Link all the nodes
  168. expectedRoot.LinkNodes();
  169. if (expectedRoot == null)
  170. {
  171. Assert.Null(actualRoot);
  172. }
  173. else
  174. {
  175. Assert.NotNull(actualRoot);
  176. EvaluateSyntaxTreeNode(collector, actualRoot, expectedRoot);
  177. if (collector.Success)
  178. {
  179. WriteTraceLine("Parse Tree Validation Succeeded:\r\n{0}", collector.Message);
  180. }
  181. else
  182. {
  183. Assert.True(false, String.Format("\r\n{0}", collector.Message));
  184. }
  185. }
  186. }
  187. private static void EvaluateSyntaxTreeNode(ErrorCollector collector, SyntaxTreeNode actual, SyntaxTreeNode expected)
  188. {
  189. if (actual == null)
  190. {
  191. AddNullActualError(collector, actual, expected);
  192. }
  193. if (actual.IsBlock != expected.IsBlock)
  194. {
  195. AddMismatchError(collector, actual, expected);
  196. }
  197. else
  198. {
  199. if (expected.IsBlock)
  200. {
  201. EvaluateBlock(collector, (Block)actual, (Block)expected);
  202. }
  203. else
  204. {
  205. EvaluateSpan(collector, (Span)actual, (Span)expected);
  206. }
  207. }
  208. }
  209. private static void EvaluateSpan(ErrorCollector collector, Span actual, Span expected)
  210. {
  211. if (!Equals(expected, actual))
  212. {
  213. AddMismatchError(collector, actual, expected);
  214. }
  215. else
  216. {
  217. AddPassedMessage(collector, expected);
  218. }
  219. }
  220. private static void EvaluateBlock(ErrorCollector collector, Block actual, Block expected)
  221. {
  222. if (actual.Type != expected.Type || !expected.CodeGenerator.Equals(actual.CodeGenerator))
  223. {
  224. AddMismatchError(collector, actual, expected);
  225. }
  226. else
  227. {
  228. AddPassedMessage(collector, expected);
  229. using (collector.Indent())
  230. {
  231. IEnumerator<SyntaxTreeNode> expectedNodes = expected.Children.GetEnumerator();
  232. IEnumerator<SyntaxTreeNode> actualNodes = actual.Children.GetEnumerator();
  233. while (expectedNodes.MoveNext())
  234. {
  235. if (!actualNodes.MoveNext())
  236. {
  237. collector.AddError("{0} - FAILED :: No more elements at this node", expectedNodes.Current);
  238. }
  239. else
  240. {
  241. EvaluateSyntaxTreeNode(collector, actualNodes.Current, expectedNodes.Current);
  242. }
  243. }
  244. while (actualNodes.MoveNext())
  245. {
  246. collector.AddError("End of Node - FAILED :: Found Node: {0}", actualNodes.Current);
  247. }
  248. }
  249. }
  250. }
  251. private static void AddPassedMessage(ErrorCollector collector, SyntaxTreeNode expected)
  252. {
  253. collector.AddMessage("{0} - PASSED", expected);
  254. }
  255. private static void AddMismatchError(ErrorCollector collector, SyntaxTreeNode actual, SyntaxTreeNode expected)
  256. {
  257. collector.AddError("{0} - FAILED :: Actual: {1}", expected, actual);
  258. }
  259. private static void AddNullActualError(ErrorCollector collector, SyntaxTreeNode actual, SyntaxTreeNode expected)
  260. {
  261. collector.AddError("{0} - FAILED :: Actual: << Null >>", expected);
  262. }
  263. public static void EvaluateRazorErrors(IList<RazorError> actualErrors, IList<RazorError> expectedErrors)
  264. {
  265. // Evaluate the errors
  266. if (expectedErrors == null || expectedErrors.Count == 0)
  267. {
  268. Assert.True(actualErrors.Count == 0,
  269. String.Format("Expected that no errors would be raised, but the following errors were:\r\n{0}", FormatErrors(actualErrors)));
  270. }
  271. else
  272. {
  273. Assert.True(expectedErrors.Count == actualErrors.Count,
  274. 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}",
  275. expectedErrors.Count,
  276. actualErrors.Count,
  277. FormatErrors(expectedErrors),
  278. FormatErrors(actualErrors)));
  279. Assert.Equal(expectedErrors.ToArray(), actualErrors.ToArray());
  280. }
  281. WriteTraceLine("Expected Errors were raised:\r\n{0}", FormatErrors(expectedErrors));
  282. }
  283. public static string FormatErrors(IList<RazorError> errors)
  284. {
  285. if (errors == null)
  286. {
  287. return "\t<< No Errors >>";
  288. }
  289. StringBuilder builder = new StringBuilder();
  290. foreach (RazorError err in errors)
  291. {
  292. builder.AppendFormat("\t{0}", err);
  293. builder.AppendLine();
  294. }
  295. return builder.ToString();
  296. }
  297. [Conditional("PARSER_TRACE")]
  298. private static void WriteTraceLine(string format, params object[] args)
  299. {
  300. Trace.WriteLine(String.Format(format, args));
  301. }
  302. protected virtual Block CreateSimpleBlockAndSpan(string spanContent, BlockType blockType, SpanKind spanType, AcceptedCharacters acceptedCharacters = AcceptedCharacters.Any)
  303. {
  304. SpanConstructor span = Factory.Span(spanType, spanContent, spanType == SpanKind.Markup).Accepts(acceptedCharacters);
  305. BlockBuilder b = new BlockBuilder()
  306. {
  307. Type = blockType
  308. };
  309. return ConfigureAndAddSpanToBlock(b, span);
  310. }
  311. protected virtual Block ConfigureAndAddSpanToBlock(BlockBuilder block, SpanConstructor span)
  312. {
  313. switch (block.Type)
  314. {
  315. case BlockType.Markup:
  316. span.With(new MarkupCodeGenerator());
  317. break;
  318. case BlockType.Statement:
  319. span.With(new StatementCodeGenerator());
  320. break;
  321. case BlockType.Expression:
  322. block.CodeGenerator = new ExpressionCodeGenerator();
  323. span.With(new ExpressionCodeGenerator());
  324. break;
  325. }
  326. block.Children.Add(span);
  327. return block.Build();
  328. }
  329. private class IgnoreOutputBlock : Block
  330. {
  331. public IgnoreOutputBlock() : base(BlockType.Template, Enumerable.Empty<SyntaxTreeNode>(), null) { }
  332. }
  333. }
  334. }