From 73dae5fcaab792a54b716f407a45417ee960dc6e Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Tue, 28 Jan 2014 17:05:48 -0800 Subject: [PATCH] Added an output validator to make a best-effort attempt at validating old and new codeDOM/codeTree output. --- .../CSharpDesignTimeHelpersVisitor.cs | 2 +- .../GeneratorResults.cs | 2 + .../RazorTemplateEngine.cs | 3 +- .../CodeTree/CodeTreeGenerationTest.cs | 3 +- .../CodeTree/CodeTreeOutputValidator.cs | 143 ++++++++++++++++++ .../Microsoft.AspNet.Razor.Test.csproj | 1 + 6 files changed, 151 insertions(+), 3 deletions(-) create mode 100644 test/Microsoft.AspNet.Razor.Test/Generator/CodeTree/CodeTreeOutputValidator.cs diff --git a/src/Microsoft.AspNet.Razor/Generator/Compiler/CodeBuilder/CSharp/Visitors/CSharpDesignTimeHelpersVisitor.cs b/src/Microsoft.AspNet.Razor/Generator/Compiler/CodeBuilder/CSharp/Visitors/CSharpDesignTimeHelpersVisitor.cs index fd6e1df1e4..09c88ddbae 100644 --- a/src/Microsoft.AspNet.Razor/Generator/Compiler/CodeBuilder/CSharp/Visitors/CSharpDesignTimeHelpersVisitor.cs +++ b/src/Microsoft.AspNet.Razor/Generator/Compiler/CodeBuilder/CSharp/Visitors/CSharpDesignTimeHelpersVisitor.cs @@ -8,7 +8,7 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp { public class CSharpDesignTimeHelpersVisitor : CodeVisitor { - private const string InheritsHelper = "__inheritsHelper"; + internal const string InheritsHelper = "__inheritsHelper"; private CSharpCodeWriter _writer; // TODO: No need for the entire host diff --git a/src/Microsoft.AspNet.Razor/GeneratorResults.cs b/src/Microsoft.AspNet.Razor/GeneratorResults.cs index 131915054f..e100105c89 100644 --- a/src/Microsoft.AspNet.Razor/GeneratorResults.cs +++ b/src/Microsoft.AspNet.Razor/GeneratorResults.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using Microsoft.AspNet.Razor.Generator; using Microsoft.AspNet.Razor.Generator.Compiler; using Microsoft.AspNet.Razor.Parser.SyntaxTree; @@ -39,6 +40,7 @@ namespace Microsoft.AspNet.Razor #if NET45 public CodeCompileUnit CCU { get; set; } + public IDictionary OLDDesignTimeLineMappings { get; set; } #endif internal CodeTree CT { get; set; } } diff --git a/src/Microsoft.AspNet.Razor/RazorTemplateEngine.cs b/src/Microsoft.AspNet.Razor/RazorTemplateEngine.cs index 6e786aad5f..551025f061 100644 --- a/src/Microsoft.AspNet.Razor/RazorTemplateEngine.cs +++ b/src/Microsoft.AspNet.Razor/RazorTemplateEngine.cs @@ -188,7 +188,8 @@ namespace Microsoft.AspNet.Razor { #if NET45 CCU = generator.Context.CompileUnit, -#endif + OLDDesignTimeLineMappings = designTimeLineMappings, +#endif CT = generator.Context.CodeTreeBuilder.CodeTree }; } diff --git a/test/Microsoft.AspNet.Razor.Test/Generator/CodeTree/CodeTreeGenerationTest.cs b/test/Microsoft.AspNet.Razor.Test/Generator/CodeTree/CodeTreeGenerationTest.cs index e8ae85fb65..76c7180b8c 100644 --- a/test/Microsoft.AspNet.Razor.Test/Generator/CodeTree/CodeTreeGenerationTest.cs +++ b/test/Microsoft.AspNet.Razor.Test/Generator/CodeTree/CodeTreeGenerationTest.cs @@ -19,9 +19,10 @@ namespace Microsoft.AspNet.Razor.Test.Generator { RunTest("CodeTree", onResults: (results, codDOMOutput) => { + CodeTreeOutputValidator.ValidateResults(results.GeneratedCode, codDOMOutput, results.DesignTimeLineMappings, results.OLDDesignTimeLineMappings); File.WriteAllText("./testfile_ct.cs", results.GeneratedCode); File.WriteAllText("./testfile_cd.cs", codDOMOutput); - }, designTimeMode: false); + }, designTimeMode: true); } } } diff --git a/test/Microsoft.AspNet.Razor.Test/Generator/CodeTree/CodeTreeOutputValidator.cs b/test/Microsoft.AspNet.Razor.Test/Generator/CodeTree/CodeTreeOutputValidator.cs new file mode 100644 index 0000000000..512bb43a7c --- /dev/null +++ b/test/Microsoft.AspNet.Razor.Test/Generator/CodeTree/CodeTreeOutputValidator.cs @@ -0,0 +1,143 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using Microsoft.AspNet.Razor.Generator; +using Microsoft.AspNet.Razor.Generator.Compiler; +using Microsoft.AspNet.Razor.Generator.Compiler.CSharp; +using Microsoft.TestCommon; + +namespace Microsoft.AspNet.Razor.Test.Generator +{ + public class CodeTreeOutputValidator + { + public static void ValidateResults(string codeTreeCode, string codeDOMCode, IList codeTreeMappings, IDictionary codeDOMMappings) + { + Assert.Equal(codeTreeMappings.Count, codeDOMMappings.Values.Count); + + ValidateNamespace(codeTreeCode, codeDOMCode); + ValidateClass(codeTreeCode, codeDOMCode); + ValidateUsings(codeTreeCode, codeDOMCode); + ValidateNewObjects(codeTreeCode, codeDOMCode); + ValidateBraces(codeTreeCode, codeDOMCode); + ValidateLambdas(codeTreeCode, codeDOMCode); + ValidateMembers(codeTreeCode, codeDOMCode); + ValidateReturns(codeTreeCode, codeDOMCode); + ValidateBaseTypes(codeTreeCode, codeDOMCode); + } + + private static void ValidateNamespace(string codeTreeCode, string codeDOMCode) + { + ValidateCodeTreeContains(codeTreeCode, codeDOMCode, @"namespace [^\s{]+"); + + } + + private static void ValidateClass(string codeTreeCode, string codeDOMCode) + { + ValidateCodeTreeContains(codeTreeCode, codeDOMCode, @"class [^\s{]+"); + } + + private static void ValidateUsings(string codeTreeCode, string codeDOMCode) + { + ValidateCodeTreeContainsAll(codeTreeCode, codeDOMCode, @"using [^\s{;]+"); + } + + private static void ValidateNewObjects(string codeTreeCode, string codeDOMCode) + { + ValidateCodeTreeContainsAll(codeTreeCode, codeDOMCode, @"new [^\(<\s]+"); + } + + private static void ValidateBraces(string codeTreeCode, string codeDOMCode) + { + var codeDOMMatches = Regex.Matches(codeDOMCode, "{"); + var codeTreeMatches = Regex.Matches(codeTreeCode, "{"); + + Assert.NotEmpty(codeDOMMatches); + Assert.NotEmpty(codeTreeMatches); + if (codeDOMMatches.Count != codeTreeMatches.Count) + { + // 1 leniency for the design time helpers + Assert.Equal(codeDOMMatches.Count, codeTreeMatches.Count - 1); + } + else + { + Assert.Equal(codeDOMMatches.Count, codeTreeMatches.Count); + } + + codeDOMMatches = Regex.Matches(codeDOMCode, "}"); + codeTreeMatches = Regex.Matches(codeTreeCode, "}"); + + Assert.NotEmpty(codeDOMMatches); + Assert.NotEmpty(codeTreeMatches); + if (codeDOMMatches.Count != codeTreeMatches.Count) + { + // 1 leniency for the design time helpers + Assert.Equal(codeDOMMatches.Count, codeTreeMatches.Count - 1); + } + else + { + Assert.Equal(codeDOMMatches.Count, codeTreeMatches.Count); + } + } + + private static void ValidateLambdas(string codeTreeCode, string codeDOMCode) + { + ValidateCount(codeTreeCode, codeDOMCode, " => "); + } + + private static void ValidateMembers(string codeTreeCode, string codeDOMCode) + { + ValidateCodeTreeContainsAll(codeTreeCode, codeDOMCode, @"(public|private) [^\s\(]+ [^\s\(]+"); + } + + private static void ValidateReturns(string codeTreeCode, string codeDOMCode) + { + ValidateCodeTreeContainsAll(codeTreeCode, codeDOMCode, @"return [^\s\(;]+"); + } + + private static void ValidateBaseTypes(string codeTreeCode, string codeDOMCode) + { + ValidateCodeTreeContainsAll(codeTreeCode, codeDOMCode, @"class [^\s]+ : [^\s{]+"); + } + + private static void ValidateKeywords(string codeTreeCode, string codeDOMCode) + { + ValidateCount(codeTreeCode, codeDOMCode, "Execute"); + ValidateCount(codeTreeCode, codeDOMCode, CSharpDesignTimeHelpersVisitor.InheritsHelper); + } + + private static void ValidateCodeTreeContains(string codeTreeCode, string codeDOMCode, string regex) + { + var match = Regex.Match(codeDOMCode, regex); + Assert.NotEmpty(match.Groups); + Assert.True(codeTreeCode.IndexOf(match.Groups[0].Value) >= 0); + } + + private static void ValidateCodeTreeContainsAll(string codeTreeCode, string codeDOMCode, string regex) + { + var matches = Regex.Matches(codeDOMCode, regex); + Assert.NotEmpty(matches); + + for (int i = 0; i < matches.Count; i++) + { + var match = matches[i]; + + for (int j = 0; j < match.Groups.Count; j++) + { + Assert.True(codeTreeCode.IndexOf(match.Groups[j].Value) >= 0); + } + } + } + + private static void ValidateCount(string codeTreeCode, string codeDOMCode, string regex) + { + var codeDOMMatches = Regex.Matches(codeDOMCode, regex); + var codeTreeMatches = Regex.Matches(codeTreeCode, regex); + + Assert.Equal(codeDOMMatches.Count, codeTreeMatches.Count); + } + } +} diff --git a/test/Microsoft.AspNet.Razor.Test/Microsoft.AspNet.Razor.Test.csproj b/test/Microsoft.AspNet.Razor.Test/Microsoft.AspNet.Razor.Test.csproj index 1a403d35e4..5b760f77c6 100644 --- a/test/Microsoft.AspNet.Razor.Test/Microsoft.AspNet.Razor.Test.csproj +++ b/test/Microsoft.AspNet.Razor.Test/Microsoft.AspNet.Razor.Test.csproj @@ -50,6 +50,7 @@ +