aspnetcore/test/Microsoft.AspNetCore.Blazor.../RazorBaselineIntegrationTes...

212 lines
8.3 KiB
C#

// 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.Linq;
using System.Threading;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.IntegrationTests;
using Xunit;
using Xunit.Sdk;
namespace Microsoft.AspNetCore.Blazor.Build.Test
{
[InitializeTestFile]
public abstract class RazorBaselineIntegrationTestBase : RazorIntegrationTestBase
{
private static readonly AsyncLocal<string> _directoryPath = new AsyncLocal<string>();
protected RazorBaselineIntegrationTestBase(bool? generateBaselines = null)
{
TestProjectRoot = TestProject.GetProjectDirectory(GetType());
if (generateBaselines.HasValue)
{
GenerateBaselines = generateBaselines.Value;
}
}
// Used by the test framework to set the directory for test files.
public static string DirectoryPath
{
get { return _directoryPath.Value; }
set { _directoryPath.Value = value; }
}
#if GENERATE_BASELINES
protected bool GenerateBaselines { get; } = true;
#else
protected bool GenerateBaselines { get; } = false;
#endif
protected string TestProjectRoot { get; }
// For consistent line endings because the character counts are going to be recorded in files.
internal override string LineEnding => "\r\n";
internal override bool NormalizeSourceLineEndings => true;
internal override string PathSeparator => "\\";
// Force consistent paths since they are going to be recorded in files.
internal override string WorkingDirectory => ArbitraryWindowsPath;
[Fact]
public void GenerateBaselinesMustBeFalse()
{
Assert.False(GenerateBaselines, "GenerateBaselines should be set back to false before you check in!");
}
protected void AssertDocumentNodeMatchesBaseline(RazorCodeDocument codeDocument)
{
var document = codeDocument.GetDocumentIntermediateNode();
var baselineFilePath = GetBaselineFilePath(codeDocument, ".ir.txt");
if (GenerateBaselines)
{
var baselineFullPath = Path.Combine(TestProjectRoot, baselineFilePath);
Directory.CreateDirectory(Path.GetDirectoryName(baselineFullPath));
WriteBaseline(IntermediateNodeSerializer.Serialize(document), baselineFullPath);
return;
}
var irFile = TestFile.Create(baselineFilePath, GetType().Assembly);
if (!irFile.Exists())
{
throw new XunitException($"The resource {baselineFilePath} was not found.");
}
// Normalize newlines by splitting into an array.
var baseline = irFile.ReadAllText().Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
IntermediateNodeVerifier.Verify(document, baseline);
}
protected void AssertCSharpDocumentMatchesBaseline(RazorCodeDocument codeDocument)
{
var document = codeDocument.GetCSharpDocument();
// Normalize newlines to match those in the baseline.
var actualCode = document.GeneratedCode.Replace("\r", "").Replace("\n", "\r\n");
var baselineFilePath = GetBaselineFilePath(codeDocument, ".codegen.cs");
var baselineDiagnosticsFilePath = GetBaselineFilePath(codeDocument, ".diagnostics.txt");
var baselineMappingsFilePath = GetBaselineFilePath(codeDocument, ".mappings.txt");
var serializedMappings = SourceMappingsSerializer.Serialize(document, codeDocument.Source);
if (GenerateBaselines)
{
var baselineFullPath = Path.Combine(TestProjectRoot, baselineFilePath);
Directory.CreateDirectory(Path.GetDirectoryName(baselineFullPath));
WriteBaseline(actualCode, baselineFullPath);
var baselineDiagnosticsFullPath = Path.Combine(TestProjectRoot, baselineDiagnosticsFilePath);
var lines = document.Diagnostics.Select(RazorDiagnosticSerializer.Serialize).ToArray();
if (lines.Any())
{
WriteBaseline(lines, baselineDiagnosticsFullPath);
}
else if (File.Exists(baselineDiagnosticsFullPath))
{
File.Delete(baselineDiagnosticsFullPath);
}
var baselineMappingsFullPath = Path.Combine(TestProjectRoot, baselineMappingsFilePath);
var text = SourceMappingsSerializer.Serialize(document, codeDocument.Source);
if (!string.IsNullOrEmpty(text))
{
WriteBaseline(text, baselineMappingsFullPath);
}
else if (File.Exists(baselineMappingsFullPath))
{
File.Delete(baselineMappingsFullPath);
}
return;
}
var codegenFile = TestFile.Create(baselineFilePath, GetType().Assembly);
if (!codegenFile.Exists())
{
throw new XunitException($"The resource {baselineFilePath} was not found.");
}
var baseline = codegenFile.ReadAllText();
Assert.Equal(baseline, actualCode);
var baselineDiagnostics = string.Empty;
var diagnosticsFile = TestFile.Create(baselineDiagnosticsFilePath, GetType().Assembly);
if (diagnosticsFile.Exists())
{
baselineDiagnostics = diagnosticsFile.ReadAllText();
}
var actualDiagnostics = string.Concat(document.Diagnostics.Select(d => RazorDiagnosticSerializer.Serialize(d) + "\r\n"));
Assert.Equal(baselineDiagnostics, actualDiagnostics);
var baselineMappings = string.Empty;
var mappingsFile = TestFile.Create(baselineMappingsFilePath, GetType().Assembly);
if (mappingsFile.Exists())
{
baselineMappings = mappingsFile.ReadAllText();
}
var actualMappings = SourceMappingsSerializer.Serialize(document, codeDocument.Source);
actualMappings = actualMappings.Replace("\r", "").Replace("\n", "\r\n");
Assert.Equal(baselineMappings, actualMappings);
}
private string GetBaselineFilePath(RazorCodeDocument codeDocument, string extension)
{
if (codeDocument == null)
{
throw new ArgumentNullException(nameof(codeDocument));
}
if (extension == null)
{
throw new ArgumentNullException(nameof(extension));
}
var lastSlash = codeDocument.Source.FilePath.LastIndexOfAny(new []{ '/', '\\' });
var fileName = lastSlash == -1 ? null : codeDocument.Source.FilePath.Substring(lastSlash + 1);
if (string.IsNullOrEmpty(fileName))
{
var message = "Integration tests require a filename";
throw new InvalidOperationException(message);
}
if (DirectoryPath == null)
{
var message = $"{nameof(AssertDocumentNodeMatchesBaseline)} should only be called from an integration test..";
throw new InvalidOperationException(message);
}
return Path.Combine(DirectoryPath, Path.ChangeExtension(fileName, extension));
}
private static void WriteBaseline(string text, string filePath)
{
var lines = text.Replace("\r", "").Replace("\n", "\r\n");
File.WriteAllText(filePath, text);
}
private static void WriteBaseline(string[] lines, string filePath)
{
using (var writer = new StreamWriter(File.Open(filePath, FileMode.Create)))
{
// Force windows-style line endings so that we're consistent. This isn't
// required for correctness, but will prevent churn when developing on OSX.
writer.NewLine = "\r\n";
for (var i = 0; i < lines.Length; i++)
{
writer.WriteLine(lines[i]);
}
}
}
}
}