Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Coverlet Intergration with VSTest #410

Merged
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions build.proj
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
<RemoveDir Directories="$(OutputPath)" Condition="Exists('$(MSBuildThisFileDirectory)\build')" />
<Exec Command="dotnet build &quot;$(MSBuildThisFileDirectory)src\coverlet.msbuild.tasks\coverlet.msbuild.tasks.csproj&quot; -c $(Configuration)" />
<Exec Command="dotnet build &quot;$(MSBuildThisFileDirectory)src\coverlet.console\coverlet.console.csproj&quot; -c $(Configuration)" />
<Exec Command="dotnet build &quot;$(MSBuildThisFileDirectory)src\coverlet.collector\coverlet.collector.csproj&quot; -c $(Configuration)" />
</Target>

<Target Name="PublishMSBuildTaskProject" AfterTargets="BuildAllProjects">
Expand All @@ -25,11 +26,13 @@

<Target Name="RunTests" AfterTargets="CopyMSBuildScripts">
<Exec Command="dotnet test &quot;$(MSBuildThisFileDirectory)test\coverlet.core.tests\coverlet.core.tests.csproj&quot; -c $(Configuration) /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Include=[coverlet.*]*"/>
<Exec Command="dotnet test &quot;$(MSBuildThisFileDirectory)test\coverlet.collector.tests\coverlet.collector.tests.csproj&quot; -c $(Configuration) /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Include=[coverlet.*]*"/>
</Target>

<Target Name="CreateNuGetPackage" AfterTargets="RunTests" Condition="$(Configuration) == 'Release'">
<Exec Command="dotnet pack &quot;$(MSBuildThisFileDirectory)src\coverlet.msbuild.tasks\coverlet.msbuild.tasks.csproj&quot; -c $(Configuration) -o $(OutputPath)" />
<Exec Command="dotnet pack &quot;$(MSBuildThisFileDirectory)src\coverlet.console\coverlet.console.csproj&quot; -c $(Configuration) -o $(OutputPath)" />
<Exec Command="dotnet pack &quot;$(MSBuildThisFileDirectory)src\coverlet.collector\coverlet.collector.csproj&quot; -c $(Configuration) -p:NuspecFile=&quot;$(MSBuildThisFileDirectory)src\coverlet.collector\coverlet.collector.nuspec&quot; -o $(OutputPath)" />
</Target>

</Project>
21 changes: 21 additions & 0 deletions coverlet.sln
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "coverlet.testsubject", "tes
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "coverlet.core.performancetest", "test\coverlet.core.performancetest\coverlet.core.performancetest.csproj", "{C68CF6DE-F86C-4BCF-BAB9-7A60C320E1F9}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "coverlet.collector", "src\coverlet.collector\coverlet.collector.csproj", "{F5B2C45B-274B-43D6-9565-8B50659CFE56}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "coverlet.inproccollector", "src\coverlet.inproccollector\coverlet.inproccollector.csproj", "{C53F1496-65AE-415D-A46B-4BA1BC45709B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "coverlet.collector.tests", "test\coverlet.collector.tests\coverlet.collector.tests.csproj", "{5ED4FA81-8F8C-4211-BA88-7573BD63262E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -49,6 +55,18 @@ Global
{C68CF6DE-F86C-4BCF-BAB9-7A60C320E1F9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C68CF6DE-F86C-4BCF-BAB9-7A60C320E1F9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C68CF6DE-F86C-4BCF-BAB9-7A60C320E1F9}.Release|Any CPU.Build.0 = Release|Any CPU
{F5B2C45B-274B-43D6-9565-8B50659CFE56}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F5B2C45B-274B-43D6-9565-8B50659CFE56}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F5B2C45B-274B-43D6-9565-8B50659CFE56}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F5B2C45B-274B-43D6-9565-8B50659CFE56}.Release|Any CPU.Build.0 = Release|Any CPU
{C53F1496-65AE-415D-A46B-4BA1BC45709B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C53F1496-65AE-415D-A46B-4BA1BC45709B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C53F1496-65AE-415D-A46B-4BA1BC45709B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C53F1496-65AE-415D-A46B-4BA1BC45709B}.Release|Any CPU.Build.0 = Release|Any CPU
{5ED4FA81-8F8C-4211-BA88-7573BD63262E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5ED4FA81-8F8C-4211-BA88-7573BD63262E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5ED4FA81-8F8C-4211-BA88-7573BD63262E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5ED4FA81-8F8C-4211-BA88-7573BD63262E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -60,6 +78,9 @@ Global
{F3DBE7C3-ABBB-4B8B-A6CB-A1D3D607163E} = {E877EBA4-E78B-4F7D-A2D3-1E070FED04CD}
{AE117FAA-C21D-4F23-917E-0C8050614750} = {2FEBDE1B-83E3-445B-B9F8-5644B0E0E134}
{C68CF6DE-F86C-4BCF-BAB9-7A60C320E1F9} = {2FEBDE1B-83E3-445B-B9F8-5644B0E0E134}
{F5B2C45B-274B-43D6-9565-8B50659CFE56} = {E877EBA4-E78B-4F7D-A2D3-1E070FED04CD}
{C53F1496-65AE-415D-A46B-4BA1BC45709B} = {E877EBA4-E78B-4F7D-A2D3-1E070FED04CD}
{5ED4FA81-8F8C-4211-BA88-7573BD63262E} = {2FEBDE1B-83E3-445B-B9F8-5644B0E0E134}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {9CA57C02-97B0-4C38-A027-EA61E8741F10}
Expand Down
156 changes: 156 additions & 0 deletions src/coverlet.collector/DataCollector/AttachmentManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
using System;
using System.ComponentModel;
using System.IO;
using coverlet.collector.Resources;
using Coverlet.Collector.Utilities;
using Coverlet.Collector.Utilities.Interfaces;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.DataCollection;

namespace Coverlet.Collector.DataCollector
{
/// <summary>
/// Manages coverage report attachments
/// </summary>
internal class AttachmentManager : IDisposable
{
private readonly DataCollectionSink dataSink;
private readonly TestPlatformEqtTrace eqtTrace;
private readonly TestPlatformLogger logger;
private readonly DataCollectionContext dataCollectionContext;
private readonly IFileHelper fileHelper;
private readonly IDirectoryHelper directoryHelper;
private readonly string reportFileName;
private readonly string reportDirectory;

public AttachmentManager(DataCollectionSink dataSink, DataCollectionContext dataCollectionContext, TestPlatformLogger logger, TestPlatformEqtTrace eqtTrace, string reportFileName)
: this(dataSink,
dataCollectionContext,
logger,
eqtTrace,
reportFileName,
Guid.NewGuid().ToString(),
new FileHelper(),
new DirectoryHelper())
{
}

public AttachmentManager(DataCollectionSink dataSink, DataCollectionContext dataCollectionContext, TestPlatformLogger logger, TestPlatformEqtTrace eqtTrace, string reportFileName, string reportDirectoryName, IFileHelper fileHelper, IDirectoryHelper directoryHelper)
{
// Store input vars
this.dataSink = dataSink;
this.dataCollectionContext = dataCollectionContext;
this.logger = logger;
this.eqtTrace = eqtTrace;
this.reportFileName = reportFileName;
this.fileHelper = fileHelper;
this.directoryHelper = directoryHelper;

// Report directory to store the coverage reports.
this.reportDirectory = Path.Combine(Path.GetTempPath(), reportDirectoryName);

// Register events
this.dataSink.SendFileCompleted += this.OnSendFileCompleted;
}

/// <summary>
/// Sends coverage report to test platform
/// </summary>
/// <param name="coverageReport">Coverage report</param>
public void SendCoverageReport(string coverageReport)
{
// Save coverage report to file
var coverageReportPath = this.SaveCoverageReport(coverageReport);

// Send coverage attachment to test platform.
this.SendAttachment(coverageReportPath);
}

/// <summary>
/// Disposes attachment manager
/// </summary>
public void Dispose()
{
// Unregister events
if (this.dataSink != null)
{
this.dataSink.SendFileCompleted -= this.OnSendFileCompleted;
}
}

/// <summary>
/// Saves coverage report to file system
/// </summary>
/// <param name="report">Coverage report</param>
/// <returns>Coverage report file path</returns>
private string SaveCoverageReport(string report)
{
try
{
this.directoryHelper.CreateDirectory(this.reportDirectory);
var filePath = Path.Combine(this.reportDirectory, this.reportFileName);
this.fileHelper.WriteAllText(filePath, report);
this.eqtTrace.Info("{0}: Saved coverage report to path: '{1}'", CoverletConstants.DataCollectorName, filePath);

return filePath;
}
catch (Exception ex)
{
var errorMessage = string.Format(Resources.FailedToSaveCoverageReport, CoverletConstants.DataCollectorName, this.reportFileName, this.reportDirectory);
throw new CoverletDataCollectorException(errorMessage, ex);
}
}

/// <summary>
/// SendFileCompleted event handler
/// </summary>
/// <param name="sender">Sender</param>
/// <param name="e">Event args</param>
public void OnSendFileCompleted(object sender, AsyncCompletedEventArgs e)
{
try
{
this.eqtTrace.Verbose("{0}: SendFileCompleted received", CoverletConstants.DataCollectorName);
this.CleanupReportDirectory();
}
catch (Exception ex)
{
this.logger.LogWarning(ex.ToString());
this.Dispose();
}
}

/// <summary>
/// Sends attachment file to test platform
/// </summary>
/// <param name="attachmentPath">Attachment file path</param>
private void SendAttachment(string attachmentPath)
{
if (this.fileHelper.Exists(attachmentPath))
{
// Send coverage attachment to test platform.
this.eqtTrace.Verbose("{0}: Sending attachment to test platform", CoverletConstants.DataCollectorName);
this.dataSink.SendFileAsync(this.dataCollectionContext, attachmentPath, false);
vagisha-nidhi marked this conversation as resolved.
Show resolved Hide resolved
}
vagisha-nidhi marked this conversation as resolved.
Show resolved Hide resolved
}

/// <summary>
/// Cleans up coverage report directory
/// </summary>
private void CleanupReportDirectory()
{
try
{
if (this.directoryHelper.Exists(this.reportDirectory))
{
this.directoryHelper.Delete(this.reportDirectory, true);
this.eqtTrace.Verbose("{0}: Deleted report directory: '{1}'", CoverletConstants.DataCollectorName, this.reportDirectory);
}
}
catch (Exception ex)
{
var errorMessage = string.Format(Resources.FailedToCleanupReportDirectory, CoverletConstants.DataCollectorName, this.reportDirectory);
throw new CoverletDataCollectorException(errorMessage, ex);
}
}
}
}
106 changes: 106 additions & 0 deletions src/coverlet.collector/DataCollector/CoverageManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
using System;
using coverlet.collector.Resources;
using Coverlet.Collector.Utilities;
using Coverlet.Collector.Utilities.Interfaces;
using Coverlet.Core;
using Coverlet.Core.Logging;
using Coverlet.Core.Reporters;

namespace Coverlet.Collector.DataCollector
{
/// <summary>
/// Manages coverlet coverage
/// </summary>
internal class CoverageManager
{
private readonly Coverage coverage;

private ICoverageWrapper coverageWrapper;

public IReporter Reporter { get; }

public CoverageManager(CoverletSettings settings, TestPlatformEqtTrace eqtTrace, TestPlatformLogger logger, ICoverageWrapper coverageWrapper)
: this(settings,
new ReporterFactory(settings.ReportFormat).CreateReporter(),
new CoverletLogger(eqtTrace, logger),
coverageWrapper)
{
}

public CoverageManager(CoverletSettings settings, IReporter reporter, ILogger logger, ICoverageWrapper coverageWrapper)
{
// Store input vars
this.Reporter = reporter;
this.coverageWrapper = coverageWrapper;

// Coverage object
this.coverage = this.coverageWrapper.CreateCoverage(settings, logger);
}

/// <summary>
/// Instrument modules
/// </summary>
public void InstrumentModules()
{
try
{
// Instrument modules
this.coverageWrapper.PrepareModules(this.coverage);
}
catch (Exception ex)
{
var errorMessage = string.Format(Resources.InstrumentationException, CoverletConstants.DataCollectorName);
throw new CoverletDataCollectorException(errorMessage, ex);
}
}

/// <summary>
/// Gets coverlet coverage report
/// </summary>
/// <returns>Coverage report</returns>
public string GetCoverageReport()
{
// Get coverage result
var coverageResult = this.GetCoverageResult();

// Get coverage report in default format
var coverageReport = this.GetCoverageReport(coverageResult);
return coverageReport;
}

/// <summary>
/// Gets coverlet coverage result
/// </summary>
/// <returns>Coverage result</returns>
private CoverageResult GetCoverageResult()
{
try
{
return this.coverageWrapper.GetCoverageResult(this.coverage);
}
catch (Exception ex)
{
var errorMessage = string.Format(Resources.CoverageResultException, CoverletConstants.DataCollectorName);
throw new CoverletDataCollectorException(errorMessage, ex);
}
}

/// <summary>
/// Gets coverage report from coverage result
/// </summary>
/// <param name="coverageResult">Coverage result</param>
/// <returns>Coverage report</returns>
private string GetCoverageReport(CoverageResult coverageResult)
{
try
{
return this.Reporter.Report(coverageResult);
}
catch (Exception ex)
{
var errorMessage = string.Format(Resources.CoverageReportException, CoverletConstants.DataCollectorName);
throw new CoverletDataCollectorException(errorMessage, ex);
}
}
}
}
55 changes: 55 additions & 0 deletions src/coverlet.collector/DataCollector/CoverageWrapper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
using Coverlet.Collector.DataCollector;
using Coverlet.Collector.Utilities.Interfaces;
using Coverlet.Core;
using Coverlet.Core.Logging;

namespace coverlet.collector.DataCollector
{
/// <summary>
/// Implementation for wrapping over Coverage class in coverlet.core
/// </summary>
internal class CoverageWrapper : ICoverageWrapper
{
/// <summary>
/// Creates a coverage object from given coverlet settings
/// </summary>
/// <param name="settings">Coverlet settings</param>
/// <param name="coverletLogger">Coverlet logger</param>
/// <returns>Coverage object</returns>
public Coverage CreateCoverage(CoverletSettings settings, ILogger coverletLogger)
{
return new Coverage(
settings.TestModule,
settings.IncludeFilters,
settings.IncludeDirectories,
settings.ExcludeFilters,
settings.ExcludeSourceFiles,
settings.ExcludeAttributes,
settings.IncludeTestAssembly,
settings.SingleHit,
settings.MergeWith,
settings.UseSourceLink,
coverletLogger);
}

/// <summary>
/// Gets the coverage result from provided coverage object
/// </summary>
/// <param name="coverage">Coverage</param>
/// <returns>The coverage result</returns>
public CoverageResult GetCoverageResult(Coverage coverage)
{
return coverage.GetCoverageResult();
}

/// <summary>
/// Prepares modules for getting coverage.
/// Wrapper over coverage.PrepareModules
/// </summary>
/// <param name="coverage"></param>
public void PrepareModules(Coverage coverage)
{
coverage.PrepareModules();
}
}
}
Loading