Files
coverlet/test/coverlet.integration.tests/BaseTest.cs
T
Marco Rossignoli caac526075 Move/Pin to 3.1 runtime (#688)
Move/Pin to 3.1 runtime
2020-01-14 14:46:22 +01:00

343 lines
14 KiB
C#

using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Xml.Linq;
using Coverlet.Core;
using Newtonsoft.Json;
using NuGet.Packaging;
using Xunit;
using Xunit.Sdk;
namespace Coverlet.Integration.Tests
{
[Flags]
enum BuildConfiguration
{
Debug = 1,
Release = 2
}
public abstract class BaseTest
{
private BuildConfiguration GetAssemblyBuildConfiguration()
{
var configurationAttribute = Assembly.GetExecutingAssembly().GetCustomAttribute<AssemblyConfigurationAttribute>();
if (configurationAttribute is null)
{
throw new ArgumentNullException("AssemblyConfigurationAttribute not found");
}
if (configurationAttribute.Configuration.Equals("Debug", StringComparison.InvariantCultureIgnoreCase))
{
return BuildConfiguration.Debug;
}
else if (configurationAttribute.Configuration.Equals("Release", StringComparison.InvariantCultureIgnoreCase))
{
return BuildConfiguration.Release;
}
else
{
throw new NotSupportedException($"Build configuration '{configurationAttribute.Configuration}' not supported");
}
}
private protected string GetPackageVersion(string filter)
{
if (!Directory.Exists($"../../../../../bin/{GetAssemblyBuildConfiguration()}/Packages"))
{
throw new DirectoryNotFoundException("Package directory not found, run 'dotnet pack' on repository root");
}
using Stream pkg = File.OpenRead(Directory.GetFiles($"../../../../../bin/{GetAssemblyBuildConfiguration()}/Packages", filter).Single());
using var reader = new PackageArchiveReader(pkg);
using Stream nuspecStream = reader.GetNuspec();
Manifest manifest = Manifest.ReadFrom(nuspecStream, false);
return manifest.Metadata.Version.OriginalVersion;
}
private protected ClonedTemplateProject CloneTemplateProject(bool cleanupOnDispose = true, string testSDKVersion = "16.4.0")
{
DirectoryInfo finalRoot = Directory.CreateDirectory(Guid.NewGuid().ToString("N"));
foreach (string file in (Directory.GetFiles($"../../../../coverlet.integration.template", "*.cs")
.Union(Directory.GetFiles($"../../../../coverlet.integration.template", "*.csproj")
.Union(Directory.GetFiles($"../../../../coverlet.integration.template", "nuget.config")))))
{
File.Copy(file, Path.Combine(finalRoot.FullName, Path.GetFileName(file)));
}
// We need to prevent the inheritance of global props/targets for template project
File.WriteAllText(Path.Combine(finalRoot.FullName, "Directory.Build.props"),
@"<?xml version=""1.0"" encoding=""utf-8""?>
<Project>
</Project>");
File.WriteAllText(Path.Combine(finalRoot.FullName, "Directory.Build.targets"),
@"<?xml version=""1.0"" encoding=""utf-8""?>
<Project>
</Project>");
AddMicrosoftNETTestSdkRef(finalRoot.FullName, testSDKVersion);
return new ClonedTemplateProject(finalRoot.FullName, cleanupOnDispose);
}
private protected bool RunCommand(string command, string arguments, out string standardOutput, out string standardError, string workingDirectory = "")
{
Debug.WriteLine($"BaseTest.RunCommand: {command} {arguments}");
ProcessStartInfo psi = new ProcessStartInfo(command, arguments);
psi.WorkingDirectory = workingDirectory;
psi.RedirectStandardError = true;
psi.RedirectStandardOutput = true;
Process commandProcess = Process.Start(psi);
if (!commandProcess.WaitForExit((int)TimeSpan.FromMinutes(5).TotalMilliseconds))
{
throw new XunitException($"Command 'dotnet {arguments}' didn't end after 5 minute");
}
standardOutput = commandProcess.StandardOutput.ReadToEnd();
standardError = commandProcess.StandardError.ReadToEnd();
return commandProcess.ExitCode == 0;
}
private protected bool DotnetCli(string arguments, out string standardOutput, out string standardError, string workingDirectory = "")
{
return RunCommand("dotnet", arguments, out standardOutput, out standardError, workingDirectory);
}
private protected void UpdateNugeConfigtWithLocalPackageFolder(string projectPath)
{
string nugetFile = Path.Combine(projectPath, "nuget.config");
if (!File.Exists(nugetFile))
{
throw new FileNotFoundException("Nuget.config not found", "nuget.config");
}
XDocument xml;
using (var nugetFileStream = File.OpenRead(nugetFile))
{
xml = XDocument.Load(nugetFileStream);
}
string localPackageFolder = Path.GetFullPath($"../../../../../bin/{GetAssemblyBuildConfiguration()}/Packages");
xml.Element("configuration")
.Element("packageSources")
.Elements()
.ElementAt(0)
.AddAfterSelf(new XElement("add", new XAttribute("key", "localCoverletPackages"), new XAttribute("value", localPackageFolder)));
xml.Save(nugetFile);
}
private protected void AddMicrosoftNETTestSdkRef(string projectPath, string version)
{
string csproj = Path.Combine(projectPath, "coverlet.integration.template.csproj");
if (!File.Exists(csproj))
{
throw new FileNotFoundException("coverlet.integration.template.csproj not found", "coverlet.integration.template.csproj");
}
XDocument xml;
using (var csprojStream = File.OpenRead(csproj))
{
xml = XDocument.Load(csprojStream);
}
xml.Element("Project")
.Element("ItemGroup")
.Add(new XElement("PackageReference", new XAttribute("Include", "Microsoft.NET.Test.Sdk"),
new XAttribute("Version", version)));
xml.Save(csproj);
}
private protected void AddCoverletMsbuildRef(string projectPath)
{
string csproj = Path.Combine(projectPath, "coverlet.integration.template.csproj");
if (!File.Exists(csproj))
{
throw new FileNotFoundException("coverlet.integration.template.csproj not found", "coverlet.integration.template.csproj");
}
XDocument xml;
using (var csprojStream = File.OpenRead(csproj))
{
xml = XDocument.Load(csprojStream);
}
string msbuildPkgVersion = GetPackageVersion("*msbuild*.nupkg");
xml.Element("Project")
.Element("ItemGroup")
.Add(new XElement("PackageReference", new XAttribute("Include", "coverlet.msbuild"), new XAttribute("Version", msbuildPkgVersion)));
xml.Save(csproj);
}
private protected void AddCoverletCollectosRef(string projectPath)
{
string csproj = Path.Combine(projectPath, "coverlet.integration.template.csproj");
if (!File.Exists(csproj))
{
throw new FileNotFoundException("coverlet.integration.template.csproj not found", "coverlet.integration.template.csproj");
}
XDocument xml;
using (var csprojStream = File.OpenRead(csproj))
{
xml = XDocument.Load(csprojStream);
}
string msbuildPkgVersion = GetPackageVersion("*collector*.nupkg");
xml.Element("Project")
.Element("ItemGroup")
.Add(new XElement("PackageReference", new XAttribute("Include", "coverlet.collector"), new XAttribute("Version", msbuildPkgVersion)));
xml.Save(csproj);
}
private protected string AddCollectorRunsettingsFile(string projectPath)
{
string runSettings =
@"<?xml version=""1.0"" encoding=""utf-8"" ?>
<RunSettings>
<DataCollectionRunSettings>
<DataCollectors>
<DataCollector friendlyName=""XPlat code coverage"" >
<Configuration>
<Format>json,cobertura</Format>
<Include>[coverletsamplelib.integration.template]*DeepThought</Include>
<!-- We need to include test assembly because test and code to cover are in same template project -->
<IncludeTestAssembly>true</IncludeTestAssembly>
</Configuration>
</DataCollector>
</DataCollectors>
</DataCollectionRunSettings>
</RunSettings>";
string runsettingsPath = Path.Combine(projectPath, "runSettings");
File.WriteAllText(runsettingsPath, runSettings);
return runsettingsPath;
}
private protected void AssertCoverage(ClonedTemplateProject clonedTemplateProject, string filter = "coverage.json")
{
bool coverageChecked = false;
foreach (string coverageFile in clonedTemplateProject.GetFiles(filter))
{
JsonConvert.DeserializeObject<Modules>(File.ReadAllText(coverageFile))
.Document("DeepThought.cs")
.Class("Coverlet.Integration.Template.DeepThought")
.Method("System.Int32 Coverlet.Integration.Template.DeepThought::AnswerToTheUltimateQuestionOfLifeTheUniverseAndEverything()")
.AssertLinesCovered((6, 1), (7, 1), (8, 1));
coverageChecked = true;
}
Assert.True(coverageChecked, "Coverage check fail");
}
private protected void UpdateProjectTargetFramework(ClonedTemplateProject project, params string[] targetFrameworks)
{
if (targetFrameworks is null || targetFrameworks.Length == 0)
{
throw new ArgumentException("Invalid targetFrameworks", nameof(targetFrameworks));
}
if (!File.Exists(project.ProjectFileNamePath))
{
throw new FileNotFoundException("coverlet.integration.template.csproj not found", "coverlet.integration.template.csproj");
}
XDocument xml;
using (var csprojStream = File.OpenRead(project.ProjectFileNamePath))
{
xml = XDocument.Load(csprojStream);
}
xml.Element("Project")
.Element("PropertyGroup")
.Element("TargetFramework")
.Remove();
XElement targetFrameworkElement;
if (targetFrameworks.Length == 1)
{
targetFrameworkElement = new XElement("TargetFramework", targetFrameworks[0]);
}
else
{
targetFrameworkElement = new XElement("TargetFrameworks", string.Join(';', targetFrameworks));
}
xml.Element("Project").Element("PropertyGroup").Add(targetFrameworkElement);
xml.Save(project.ProjectFileNamePath);
}
private protected void PinSDK(ClonedTemplateProject project, string sdkVersion)
{
if (project is null)
{
throw new ArgumentNullException(nameof(project));
}
if (string.IsNullOrEmpty(sdkVersion))
{
throw new ArgumentException("Invalid sdkVersion", nameof(sdkVersion));
}
if (!File.Exists(project.ProjectFileNamePath))
{
throw new FileNotFoundException("coverlet.integration.template.csproj not found", "coverlet.integration.template.csproj");
}
if (project.ProjectRootPath is null || !Directory.Exists(project.ProjectRootPath))
{
throw new ArgumentException("Invalid ProjectRootPath");
}
File.WriteAllText(Path.Combine(project.ProjectRootPath, "global.json"), $"{{ \"sdk\": {{ \"version\": \"{sdkVersion}\" }} }}");
}
}
class ClonedTemplateProject : IDisposable
{
public string ProjectRootPath { get; private set; }
public bool CleanupOnDispose { get; private set; }
// We need to have a different asm name to avoid issue with collectors, we filter [coverlet.*]* by default
// https://github.com/tonerdo/coverlet/pull/410#discussion_r284526728
public static string AssemblyName { get; } = "coverletsamplelib.integration.template";
public static string ProjectFileName { get; } = "coverlet.integration.template.csproj";
public string ProjectFileNamePath => Path.Combine(ProjectRootPath, "coverlet.integration.template.csproj");
public ClonedTemplateProject(string? projectRootPath, bool cleanupOnDispose)
{
ProjectRootPath = (projectRootPath ?? throw new ArgumentNullException(nameof(projectRootPath)));
CleanupOnDispose = cleanupOnDispose;
}
public bool IsMultipleTargetFramework()
{
using var csprojStream = File.OpenRead(ProjectFileNamePath);
XDocument xml = XDocument.Load(csprojStream);
return xml.Element("Project").Element("PropertyGroup").Element("TargetFramework") == null;
}
public string[] GetTargetFrameworks()
{
using var csprojStream = File.OpenRead(ProjectFileNamePath);
XDocument xml = XDocument.Load(csprojStream);
XElement element = xml.Element("Project").Element("PropertyGroup").Element("TargetFramework") ?? xml.Element("Project").Element("PropertyGroup").Element("TargetFrameworks");
if (element is null)
{
throw new ArgumentNullException("No 'TargetFramework' neither 'TargetFrameworks' found in csproj file");
}
return element.Value.Split(";");
}
public string[] GetFiles(string filter)
{
return Directory.GetFiles(ProjectRootPath, filter, SearchOption.AllDirectories);
}
public void Dispose()
{
if (CleanupOnDispose)
{
Directory.Delete(ProjectRootPath, true);
}
}
}
}