diff --git a/test/Microsoft.AspNet.Razor.Test/CodeGenerators/CSharpCodeGeneratorTest.cs b/test/Microsoft.AspNet.Razor.Test/CodeGenerators/CSharpCodeGeneratorTest.cs index b591f025eb..436a18acf5 100644 --- a/test/Microsoft.AspNet.Razor.Test/CodeGenerators/CSharpCodeGeneratorTest.cs +++ b/test/Microsoft.AspNet.Razor.Test/CodeGenerators/CSharpCodeGeneratorTest.cs @@ -2,6 +2,9 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. #if !DNXCORE50 +#if GENERATE_BASELINES +using System; +#endif using Microsoft.AspNet.Razor.Parser.SyntaxTree; using Microsoft.AspNet.Razor.Test; using Microsoft.AspNet.Razor.Test.Generator; @@ -29,18 +32,37 @@ namespace Microsoft.AspNet.Razor.CodeGenerators codeGeneratorContext.ChunkTreeBuilder.AddUsingChunk("FakeNamespace1", syntaxTreeNode.Object); codeGeneratorContext.ChunkTreeBuilder.AddUsingChunk("FakeNamespace2.SubNamespace", syntaxTreeNode.Object); var codeGenerator = new CodeGenTestCodeGenerator(codeGeneratorContext); + var testFile = TestFile.Create("TestFiles/CodeGenerator/Output/CSharpCodeGenerator.cs"); + + string expectedOutput; +#if GENERATE_BASELINES + if (testFile.Exists()) + { + expectedOutput = testFile.ReadAllText(); + } + else + { + expectedOutput = null; + } +#else + expectedOutput = testFile.ReadAllText(); +#endif // Act var result = codeGenerator.Generate(); - BaselineWriter.WriteBaseline( - @"test\Microsoft.AspNet.Razor.Test\TestFiles\CodeGenerator\Output\CSharpCodeGenerator.cs", - result.Code); - - var expectedOutput = TestFile.Create("TestFiles/CodeGenerator/Output/CSharpCodeGenerator.cs").ReadAllText(); - // Assert +#if GENERATE_BASELINES + // Update baseline files if files do not already match. + if (!string.Equals(expectedOutput, result.Code, StringComparison.Ordinal)) + { + BaselineWriter.WriteBaseline( + @"test\Microsoft.AspNet.Razor.Test\TestFiles\CodeGenerator\Output\CSharpCodeGenerator.cs", + result.Code); + } +#else Assert.Equal(expectedOutput, result.Code); +#endif } } } diff --git a/test/Microsoft.AspNet.Razor.Test/CodeGenerators/RazorChunkGeneratorTest.cs b/test/Microsoft.AspNet.Razor.Test/CodeGenerators/RazorChunkGeneratorTest.cs index b2bbed4cdd..735f7f87f0 100644 --- a/test/Microsoft.AspNet.Razor.Test/CodeGenerators/RazorChunkGeneratorTest.cs +++ b/test/Microsoft.AspNet.Razor.Test/CodeGenerators/RazorChunkGeneratorTest.cs @@ -127,9 +127,22 @@ namespace Microsoft.AspNet.Razor.Test.Generator } var sourceLocation = string.Format("TestFiles/CodeGenerator/Source/{0}.{1}", name, FileExtension); - var expectedOutput = TestFile - .Create(string.Format("TestFiles/CodeGenerator/Output/{0}.{1}", baselineName, BaselineExtension)) - .ReadAllText(); + var testFile = TestFile + .Create(string.Format("TestFiles/CodeGenerator/Output/{0}.{1}", baselineName, BaselineExtension)); + + string expectedOutput; +#if GENERATE_BASELINES + if (testFile.Exists()) + { + expectedOutput = testFile.ReadAllText(); + } + else + { + expectedOutput = null; + } +#else + expectedOutput = testFile.ReadAllText(); +#endif // Set up the host and engine var host = CreateHost(); @@ -179,17 +192,20 @@ namespace Microsoft.AspNet.Razor.Test.Generator rootNamespace: TestRootNamespaceName, sourceFileName: sourceFileName); } - // Only called if GENERATE_BASELINES is set, otherwise compiled out. - BaselineWriter.WriteBaseline( - string.Format( - @"test\Microsoft.AspNet.Razor.Test\TestFiles\ChunkGenerator\Output\{0}.{1}", - baselineName, - BaselineExtension), - results.GeneratedCode); -#if !GENERATE_BASELINES var textOutput = results.GeneratedCode; +#if GENERATE_BASELINES + var outputFile = string.Format( + @"test\Microsoft.AspNet.Razor.Test\TestFiles\CodeGenerator\Output\{0}.{1}", + baselineName, + BaselineExtension); + // Update baseline files if files do not already match. + if (!string.Equals(expectedOutput, textOutput, StringComparison.Ordinal)) + { + BaselineWriter.WriteBaseline(outputFile, textOutput); + } +#else if (onResults != null) { onResults(results); @@ -216,17 +232,70 @@ namespace Microsoft.AspNet.Razor.Test.Generator if (expectedDesignTimePragmas != null) { - Assert.True(results.DesignTimeLineMappings != null); // Guard + Assert.NotNull(results.DesignTimeLineMappings); // Guard +#if GENERATE_BASELINES + if (expectedDesignTimePragmas == null || + !Enumerable.SequenceEqual(expectedDesignTimePragmas, results.DesignTimeLineMappings)) + { + var lineMappingFile = Path.ChangeExtension(outputFile, "lineMappings.cs"); + var lineMappingCode = GetDesignTimeLineMappingsCode(results.DesignTimeLineMappings); + BaselineWriter.WriteBaseline(lineMappingFile, lineMappingCode); + } +#else for (var i = 0; i < expectedDesignTimePragmas.Count && i < results.DesignTimeLineMappings.Count; i++) { Assert.Equal(expectedDesignTimePragmas[i], results.DesignTimeLineMappings[i]); } Assert.Equal(expectedDesignTimePragmas.Count, results.DesignTimeLineMappings.Count); +#endif } } } + private static string GetDesignTimeLineMappingsCode(IList designTimeLineMappings) + { + var lineMappings = new StringBuilder(); + lineMappings.AppendLine($"// !!! Do not check in. Instead paste content into test method. !!!"); + lineMappings.AppendLine(); + + var indent = " "; + lineMappings.AppendLine($"{ indent }var expectedLineMappings = new[]"); + lineMappings.AppendLine($"{ indent }{{"); + foreach (var lineMapping in designTimeLineMappings) + { + var innerIndent = indent + " "; + var documentLocation = lineMapping.DocumentLocation; + var generatedLocation = lineMapping.GeneratedLocation; + lineMappings.AppendLine($"{ innerIndent }BuildLineMapping("); + + innerIndent += " "; + lineMappings.AppendLine($"{ innerIndent }documentAbsoluteIndex: { documentLocation.AbsoluteIndex },"); + lineMappings.AppendLine($"{ innerIndent }documentLineIndex: { documentLocation.LineIndex },"); + if (documentLocation.CharacterIndex != generatedLocation.CharacterIndex) + { + lineMappings.AppendLine($"{ innerIndent }documentCharacterOffsetIndex: { documentLocation.CharacterIndex },"); + } + + lineMappings.AppendLine($"{ innerIndent }generatedAbsoluteIndex: { generatedLocation.AbsoluteIndex },"); + lineMappings.AppendLine($"{ innerIndent }generatedLineIndex: { generatedLocation.LineIndex },"); + if (documentLocation.CharacterIndex != generatedLocation.CharacterIndex) + { + lineMappings.AppendLine($"{ innerIndent }generatedCharacterOffsetIndex: { generatedLocation.CharacterIndex },"); + } + else + { + lineMappings.AppendLine($"{ innerIndent }characterOffsetIndex: { generatedLocation.CharacterIndex },"); + } + + lineMappings.AppendLine($"{ innerIndent }contentLength: { generatedLocation.ContentLength }),"); + } + + lineMappings.AppendLine($"{ indent }}};"); + + return lineMappings.ToString(); + } + private void VerifyNoBrokenEndOfLines(string text) { for (int i = 0; i < text.Length; i++) diff --git a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/CodeBlockWithTextElement.cs b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/CodeBlockWithTextElement.cs index 0415b68191..fd92a4b060 100644 --- a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/CodeBlockWithTextElement.cs +++ b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/Output/CodeBlockWithTextElement.cs @@ -1,4 +1,4 @@ -#pragma checksum "CodeBlockWithTextElement.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "13e48ff59aab8106ceb68dd4a10b0bdf10c322fc" +#pragma checksum "CodeBlockWithTextElement.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "13e48ff59aab8106ceb68dd4a10b0bdf10c322fc" namespace TestOutput { using System; diff --git a/test/Microsoft.AspNet.Razor.Test/Utils/BaselineWriter.cs b/test/Microsoft.AspNet.Razor.Test/Utils/BaselineWriter.cs index f699812c6c..9caf811ed1 100644 --- a/test/Microsoft.AspNet.Razor.Test/Utils/BaselineWriter.cs +++ b/test/Microsoft.AspNet.Razor.Test/Utils/BaselineWriter.cs @@ -8,19 +8,26 @@ namespace Microsoft.AspNet.Razor.Test.Utils { public static class BaselineWriter { + private static object baselineLock = new object(); + [Conditional("GENERATE_BASELINES")] public static void WriteBaseline(string baselineFile, string output) { var root = RecursiveFind("Razor.sln", Path.GetFullPath(".")); var 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)) + // Serialize writes to minimize contention for file handles and directory access. + lock (baselineLock) { - File.Delete(baselinePath); + // Update baseline + using (var stream = File.Open(baselinePath, FileMode.Create, FileAccess.Write)) + { + using (var writer = new StreamWriter(stream)) + { + writer.Write(output); + } + } } - File.WriteAllText(baselinePath, output.ToString()); } private static string RecursiveFind(string path, string start) diff --git a/test/Microsoft.AspNet.Razor.Test/Utils/TestFile.cs b/test/Microsoft.AspNet.Razor.Test/Utils/TestFile.cs index 76a40c9698..df40ac6bb2 100644 --- a/test/Microsoft.AspNet.Razor.Test/Utils/TestFile.cs +++ b/test/Microsoft.AspNet.Razor.Test/Utils/TestFile.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System; using System.IO; using System.Reflection; using Xunit; @@ -9,16 +10,15 @@ namespace Microsoft.AspNet.Razor.Test { public class TestFile { - public const string ResourceNameFormat = "{0}.TestFiles.{1}"; + public TestFile(string resourceName, Assembly assembly) + { + Assembly = assembly; + ResourceName = Assembly.GetName().Name + "." + resourceName.Replace('/', '.'); + } + + public Assembly Assembly { get; } public string ResourceName { get; } - public Assembly Assembly { get; set; } - - public TestFile(string resName, Assembly asm) - { - Assembly = asm; - ResourceName = Assembly.GetName().Name + "." + resName.Replace('/', '.'); - } public static TestFile Create(string localResourceName) { @@ -27,27 +27,44 @@ namespace Microsoft.AspNet.Razor.Test public Stream OpenRead() { - var strm = Assembly.GetManifestResourceStream(ResourceName); - if (strm == null) + var stream = Assembly.GetManifestResourceStream(ResourceName); + if (stream == null) { Assert.True(false, string.Format("Manifest resource: {0} not found", ResourceName)); } - return strm; + + return stream; + } + + public bool Exists() + { + var resourceNames = Assembly.GetManifestResourceNames(); + foreach (var resourceName in resourceNames) + { + // Resource names are case-sensitive. + if (string.Equals(ResourceName, resourceName, StringComparison.Ordinal)) + { + return true; + } + } + + return false; } public byte[] ReadAllBytes() { - using (Stream stream = OpenRead()) + using (var stream = OpenRead()) { - byte[] buffer = new byte[stream.Length]; + var buffer = new byte[stream.Length]; stream.Read(buffer, 0, buffer.Length); + return buffer; } } public string ReadAllText() { - using (StreamReader reader = new StreamReader(OpenRead())) + using (var reader = new StreamReader(OpenRead())) { // The .Replace() calls normalize line endings, in case you get \n instead of \r\n // since all the unit tests rely on the assumption that the files will have \r\n endings. @@ -66,9 +83,9 @@ namespace Microsoft.AspNet.Razor.Test Directory.CreateDirectory(directory); } - using (Stream outStream = File.Create(filePath)) + using (var outStream = File.Create(filePath)) { - using (Stream inStream = OpenRead()) + using (var inStream = OpenRead()) { inStream.CopyTo(outStream); }