Avoid errors when generating baselines
- ignore missing expected output resources in this mode - update `BaselineWriter` to avoid `IOException`s (file access issues) - serialize file operations - one file handle per file - repeatedly `rm TestFiles/CodeGenerator/Output/*; `dnx . test`; no errors also - add generation of design-time line mappings - fix ChunkGenerator -> CodeGenerator typo in path names - update files only if they have changed - new `TestFiles.Exists()` method to support this check - do not check results in `CSharpCodeBuilderTests` if `GENERATE_BASELINES` set nits: - update BOM in CodeBlockWithTextElement.cs to avoid future `git diff`s - use more `var` and improve variable names in `TestFile` - wrap long lines
This commit is contained in:
parent
1e5ad1154d
commit
d545f47fe4
|
|
@ -2,6 +2,9 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
#if !DNXCORE50
|
#if !DNXCORE50
|
||||||
|
#if GENERATE_BASELINES
|
||||||
|
using System;
|
||||||
|
#endif
|
||||||
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
|
using Microsoft.AspNet.Razor.Parser.SyntaxTree;
|
||||||
using Microsoft.AspNet.Razor.Test;
|
using Microsoft.AspNet.Razor.Test;
|
||||||
using Microsoft.AspNet.Razor.Test.Generator;
|
using Microsoft.AspNet.Razor.Test.Generator;
|
||||||
|
|
@ -29,18 +32,37 @@ namespace Microsoft.AspNet.Razor.CodeGenerators
|
||||||
codeGeneratorContext.ChunkTreeBuilder.AddUsingChunk("FakeNamespace1", syntaxTreeNode.Object);
|
codeGeneratorContext.ChunkTreeBuilder.AddUsingChunk("FakeNamespace1", syntaxTreeNode.Object);
|
||||||
codeGeneratorContext.ChunkTreeBuilder.AddUsingChunk("FakeNamespace2.SubNamespace", syntaxTreeNode.Object);
|
codeGeneratorContext.ChunkTreeBuilder.AddUsingChunk("FakeNamespace2.SubNamespace", syntaxTreeNode.Object);
|
||||||
var codeGenerator = new CodeGenTestCodeGenerator(codeGeneratorContext);
|
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
|
// Act
|
||||||
var result = codeGenerator.Generate();
|
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
|
// 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);
|
Assert.Equal(expectedOutput, result.Code);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -127,9 +127,22 @@ namespace Microsoft.AspNet.Razor.Test.Generator
|
||||||
}
|
}
|
||||||
|
|
||||||
var sourceLocation = string.Format("TestFiles/CodeGenerator/Source/{0}.{1}", name, FileExtension);
|
var sourceLocation = string.Format("TestFiles/CodeGenerator/Source/{0}.{1}", name, FileExtension);
|
||||||
var expectedOutput = TestFile
|
var testFile = TestFile
|
||||||
.Create(string.Format("TestFiles/CodeGenerator/Output/{0}.{1}", baselineName, BaselineExtension))
|
.Create(string.Format("TestFiles/CodeGenerator/Output/{0}.{1}", baselineName, BaselineExtension));
|
||||||
.ReadAllText();
|
|
||||||
|
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
|
// Set up the host and engine
|
||||||
var host = CreateHost();
|
var host = CreateHost();
|
||||||
|
|
@ -179,17 +192,20 @@ namespace Microsoft.AspNet.Razor.Test.Generator
|
||||||
rootNamespace: TestRootNamespaceName,
|
rootNamespace: TestRootNamespaceName,
|
||||||
sourceFileName: sourceFileName);
|
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;
|
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)
|
if (onResults != null)
|
||||||
{
|
{
|
||||||
onResults(results);
|
onResults(results);
|
||||||
|
|
@ -216,17 +232,70 @@ namespace Microsoft.AspNet.Razor.Test.Generator
|
||||||
|
|
||||||
if (expectedDesignTimePragmas != null)
|
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++)
|
for (var i = 0; i < expectedDesignTimePragmas.Count && i < results.DesignTimeLineMappings.Count; i++)
|
||||||
{
|
{
|
||||||
Assert.Equal(expectedDesignTimePragmas[i], results.DesignTimeLineMappings[i]);
|
Assert.Equal(expectedDesignTimePragmas[i], results.DesignTimeLineMappings[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
Assert.Equal(expectedDesignTimePragmas.Count, results.DesignTimeLineMappings.Count);
|
Assert.Equal(expectedDesignTimePragmas.Count, results.DesignTimeLineMappings.Count);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string GetDesignTimeLineMappingsCode(IList<LineMapping> 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)
|
private void VerifyNoBrokenEndOfLines(string text)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < text.Length; i++)
|
for (int i = 0; i < text.Length; i++)
|
||||||
|
|
|
||||||
|
|
@ -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
|
namespace TestOutput
|
||||||
{
|
{
|
||||||
using System;
|
using System;
|
||||||
|
|
|
||||||
|
|
@ -8,19 +8,26 @@ namespace Microsoft.AspNet.Razor.Test.Utils
|
||||||
{
|
{
|
||||||
public static class BaselineWriter
|
public static class BaselineWriter
|
||||||
{
|
{
|
||||||
|
private static object baselineLock = new object();
|
||||||
|
|
||||||
[Conditional("GENERATE_BASELINES")]
|
[Conditional("GENERATE_BASELINES")]
|
||||||
public static void WriteBaseline(string baselineFile, string output)
|
public static void WriteBaseline(string baselineFile, string output)
|
||||||
{
|
{
|
||||||
var root = RecursiveFind("Razor.sln", Path.GetFullPath("."));
|
var root = RecursiveFind("Razor.sln", Path.GetFullPath("."));
|
||||||
var baselinePath = Path.Combine(root, baselineFile);
|
var baselinePath = Path.Combine(root, baselineFile);
|
||||||
|
|
||||||
// Update baseline
|
// Serialize writes to minimize contention for file handles and directory access.
|
||||||
// IMPORTANT! Replace this path with the local path on your machine to the baseline files!
|
lock (baselineLock)
|
||||||
if (File.Exists(baselinePath))
|
|
||||||
{
|
{
|
||||||
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)
|
private static string RecursiveFind(string path, string start)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// 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.
|
// 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.IO;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
@ -9,16 +10,15 @@ namespace Microsoft.AspNet.Razor.Test
|
||||||
{
|
{
|
||||||
public class TestFile
|
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 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)
|
public static TestFile Create(string localResourceName)
|
||||||
{
|
{
|
||||||
|
|
@ -27,27 +27,44 @@ namespace Microsoft.AspNet.Razor.Test
|
||||||
|
|
||||||
public Stream OpenRead()
|
public Stream OpenRead()
|
||||||
{
|
{
|
||||||
var strm = Assembly.GetManifestResourceStream(ResourceName);
|
var stream = Assembly.GetManifestResourceStream(ResourceName);
|
||||||
if (strm == null)
|
if (stream == null)
|
||||||
{
|
{
|
||||||
Assert.True(false, string.Format("Manifest resource: {0} not found", ResourceName));
|
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()
|
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);
|
stream.Read(buffer, 0, buffer.Length);
|
||||||
|
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string ReadAllText()
|
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
|
// 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.
|
// 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);
|
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);
|
inStream.CopyTo(outStream);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue