aspnetcore/test/Microsoft.AspNetCore.Razor..../IntegrationTests/IntegrationTestBase.cs

214 lines
7.6 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.Collections.Generic;
using System.IO;
using System.Reflection;
#if NET451
using System.Runtime.Remoting;
using System.Runtime.Remoting.Messaging;
#else
using System.Threading;
#endif
using System.Text;
using Microsoft.AspNetCore.Razor.Evolution.Intermediate;
using Microsoft.AspNetCore.Razor.Evolution.Legacy;
using Xunit;
using Xunit.Sdk;
using System.Runtime.InteropServices;
namespace Microsoft.AspNetCore.Razor.Evolution.IntegrationTests
{
[IntializeTestFile]
public abstract class IntegrationTestBase
{
private static readonly string ThisProjectName = typeof(IntializeTestFileAttribute).GetTypeInfo().Assembly.GetName().Name;
private static readonly string TestProjectRoot = FindTestProjectRoot();
private static string FindTestProjectRoot()
{
#if NET451
var currentDirectory = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory);
#else
var currentDirectory = new DirectoryInfo(AppContext.BaseDirectory);
#endif
while (currentDirectory != null &&
!string.Equals(currentDirectory.Name, ThisProjectName, StringComparison.Ordinal))
{
currentDirectory = currentDirectory.Parent;
}
var normalizedSeparators = currentDirectory.FullName.Replace(Path.DirectorySeparatorChar, '/');
return currentDirectory.FullName;
}
#if GENERATE_BASELINES
private static readonly bool GenerateBaselines = true;
#else
private static readonly bool GenerateBaselines = false;
#endif
#if !NET451
private static readonly AsyncLocal<string> _filename = new AsyncLocal<string>();
#endif
// Used by the test framework to set the 'base' name for test files.
public static string Filename
{
#if NET451
get
{
var handle = (ObjectHandle)CallContext.LogicalGetData("IntegrationTestBase_Filename");
return (string)handle.Unwrap();
}
set
{
CallContext.LogicalSetData("IntegrationTestBase_Filename", new ObjectHandle(value));
}
#else
get { return _filename.Value; }
set { _filename.Value = value; }
#endif
}
protected virtual RazorCodeDocument CreateCodeDocument()
{
if (Filename == null)
{
var message = $"{nameof(CreateCodeDocument)} should only be called from an integration test ({nameof(Filename)} is null).";
throw new InvalidOperationException(message);
}
var sourceFilename = Path.ChangeExtension(Filename, ".cshtml");
var testFile = TestFile.Create(sourceFilename);
if (!testFile.Exists())
{
throw new XunitException($"The resource {sourceFilename} was not found.");
}
var codeDocument = RazorCodeDocument.Create(TestRazorSourceDocument.CreateResource(sourceFilename));
// This will ensure that we're not putting any randomly generated data in a baseline.
codeDocument.Items[DefaultRazorRuntimeCSharpLoweringPhase.SuppressUniqueIds] = "test";
return codeDocument;
}
protected void AssertIRMatchesBaseline(DocumentIRNode document)
{
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
return;
}
if (Filename == null)
{
var message = $"{nameof(AssertIRMatchesBaseline)} should only be called from an integration test ({nameof(Filename)} is null).";
throw new InvalidOperationException(message);
}
var baselineFilename = Path.ChangeExtension(Filename, ".ir.txt");
if (GenerateBaselines)
{
var baselineFullPath = Path.Combine(TestProjectRoot, baselineFilename);
File.WriteAllText(baselineFullPath, RazorIRNodeSerializer.Serialize(document));
return;
}
var testFile = TestFile.Create(baselineFilename);
if (!testFile.Exists())
{
throw new XunitException($"The resource {baselineFilename} was not found.");
}
var baseline = testFile.ReadAllText().Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
RazorIRNodeVerifier.Verify(document, baseline);
}
protected void AssertCSharpDocumentMatchesBaseline(RazorCSharpDocument document)
{
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
return;
}
if (Filename == null)
{
var message = $"{nameof(AssertCSharpDocumentMatchesBaseline)} should only be called from an integration test ({nameof(Filename)} is null).";
throw new InvalidOperationException(message);
}
var baselineFilename = Path.ChangeExtension(Filename, ".codegen.cs");
if (GenerateBaselines)
{
var baselineFullPath = Path.Combine(TestProjectRoot, baselineFilename);
File.WriteAllText(baselineFullPath, document.GeneratedCode);
return;
}
var testFile = TestFile.Create(baselineFilename);
if (!testFile.Exists())
{
throw new XunitException($"The resource {baselineFilename} was not found.");
}
var baseline = testFile.ReadAllText();
// Normalize newlines to match those in the baseline.
var actual = document.GeneratedCode.Replace("\r", "").Replace("\n", "\r\n");
Assert.Equal(baseline, actual);
}
protected void AssertDesignTimeDocumentMatchBaseline(RazorCodeDocument document)
{
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
return;
}
if (Filename == null)
{
var message = $"{nameof(AssertDesignTimeDocumentMatchBaseline)} should only be called from an integration test ({nameof(Filename)} is null).";
throw new InvalidOperationException(message);
}
var csharpDocument = document.GetCSharpDocument();
Assert.NotNull(csharpDocument);
var syntaxTree = document.GetSyntaxTree();
Assert.NotNull(syntaxTree);
Assert.True(syntaxTree.Options.DesignTimeMode);
// Validate generated code.
AssertCSharpDocumentMatchesBaseline(csharpDocument);
var baselineFilename = Path.ChangeExtension(Filename, ".mappings.txt");
var serializedMappings = LineMappingsSerializer.Serialize(csharpDocument, document.Source);
if (GenerateBaselines)
{
var baselineFullPath = Path.Combine(TestProjectRoot, baselineFilename);
File.WriteAllText(baselineFullPath, serializedMappings);
return;
}
var testFile = TestFile.Create(baselineFilename);
if (!testFile.Exists())
{
throw new XunitException($"The resource {baselineFilename} was not found.");
}
var baseline = testFile.ReadAllText();
// Normalize newlines to match those in the baseline.
var actual = serializedMappings.Replace("\r", "").Replace("\n", "\r\n");
Assert.Equal(baseline, actual);
}
}
}