Skip to content

Commit b3e349e

Browse files
authored
Merge pull request #410 from vagisha-nidhi/coverletDatacollectors
Coverlet Intergration with VSTest
2 parents 33fad1e + 56855bc commit b3e349e

29 files changed

+1949
-0
lines changed

build.proj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
<RemoveDir Directories="$(OutputPath)" Condition="Exists('$(MSBuildThisFileDirectory)\build')" />
1010
<Exec Command="dotnet build &quot;$(MSBuildThisFileDirectory)src\coverlet.msbuild.tasks\coverlet.msbuild.tasks.csproj&quot; -c $(Configuration)" />
1111
<Exec Command="dotnet build &quot;$(MSBuildThisFileDirectory)src\coverlet.console\coverlet.console.csproj&quot; -c $(Configuration)" />
12+
<Exec Command="dotnet build &quot;$(MSBuildThisFileDirectory)src\coverlet.collector\coverlet.collector.csproj&quot; -c $(Configuration)" />
1213
</Target>
1314

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

2627
<Target Name="RunTests" AfterTargets="CopyMSBuildScripts">
2728
<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.*]*"/>
29+
<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.*]*"/>
2830
</Target>
2931

3032
<Target Name="CreateNuGetPackage" AfterTargets="RunTests" Condition="$(Configuration) == 'Release'">
3133
<Exec Command="dotnet pack &quot;$(MSBuildThisFileDirectory)src\coverlet.msbuild.tasks\coverlet.msbuild.tasks.csproj&quot; -c $(Configuration) -o $(OutputPath)" />
3234
<Exec Command="dotnet pack &quot;$(MSBuildThisFileDirectory)src\coverlet.console\coverlet.console.csproj&quot; -c $(Configuration) -o $(OutputPath)" />
35+
<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)" />
3336
</Target>
3437

3538
</Project>

coverlet.sln

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "coverlet.testsubject", "tes
1919
EndProject
2020
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "coverlet.core.performancetest", "test\coverlet.core.performancetest\coverlet.core.performancetest.csproj", "{C68CF6DE-F86C-4BCF-BAB9-7A60C320E1F9}"
2121
EndProject
22+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "coverlet.collector", "src\coverlet.collector\coverlet.collector.csproj", "{F5B2C45B-274B-43D6-9565-8B50659CFE56}"
23+
EndProject
24+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "coverlet.collector.tests", "test\coverlet.collector.tests\coverlet.collector.tests.csproj", "{5ED4FA81-8F8C-4211-BA88-7573BD63262E}"
25+
EndProject
2226
Global
2327
GlobalSection(SolutionConfigurationPlatforms) = preSolution
2428
Debug|Any CPU = Debug|Any CPU
@@ -49,6 +53,14 @@ Global
4953
{C68CF6DE-F86C-4BCF-BAB9-7A60C320E1F9}.Debug|Any CPU.Build.0 = Debug|Any CPU
5054
{C68CF6DE-F86C-4BCF-BAB9-7A60C320E1F9}.Release|Any CPU.ActiveCfg = Release|Any CPU
5155
{C68CF6DE-F86C-4BCF-BAB9-7A60C320E1F9}.Release|Any CPU.Build.0 = Release|Any CPU
56+
{F5B2C45B-274B-43D6-9565-8B50659CFE56}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
57+
{F5B2C45B-274B-43D6-9565-8B50659CFE56}.Debug|Any CPU.Build.0 = Debug|Any CPU
58+
{F5B2C45B-274B-43D6-9565-8B50659CFE56}.Release|Any CPU.ActiveCfg = Release|Any CPU
59+
{F5B2C45B-274B-43D6-9565-8B50659CFE56}.Release|Any CPU.Build.0 = Release|Any CPU
60+
{5ED4FA81-8F8C-4211-BA88-7573BD63262E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
61+
{5ED4FA81-8F8C-4211-BA88-7573BD63262E}.Debug|Any CPU.Build.0 = Debug|Any CPU
62+
{5ED4FA81-8F8C-4211-BA88-7573BD63262E}.Release|Any CPU.ActiveCfg = Release|Any CPU
63+
{5ED4FA81-8F8C-4211-BA88-7573BD63262E}.Release|Any CPU.Build.0 = Release|Any CPU
5264
EndGlobalSection
5365
GlobalSection(SolutionProperties) = preSolution
5466
HideSolutionNode = FALSE
@@ -60,6 +72,8 @@ Global
6072
{F3DBE7C3-ABBB-4B8B-A6CB-A1D3D607163E} = {E877EBA4-E78B-4F7D-A2D3-1E070FED04CD}
6173
{AE117FAA-C21D-4F23-917E-0C8050614750} = {2FEBDE1B-83E3-445B-B9F8-5644B0E0E134}
6274
{C68CF6DE-F86C-4BCF-BAB9-7A60C320E1F9} = {2FEBDE1B-83E3-445B-B9F8-5644B0E0E134}
75+
{F5B2C45B-274B-43D6-9565-8B50659CFE56} = {E877EBA4-E78B-4F7D-A2D3-1E070FED04CD}
76+
{5ED4FA81-8F8C-4211-BA88-7573BD63262E} = {2FEBDE1B-83E3-445B-B9F8-5644B0E0E134}
6377
EndGlobalSection
6478
GlobalSection(ExtensibilityGlobals) = postSolution
6579
SolutionGuid = {9CA57C02-97B0-4C38-A027-EA61E8741F10}
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
using System;
2+
using System.ComponentModel;
3+
using System.IO;
4+
using coverlet.collector.Resources;
5+
using Coverlet.Collector.Utilities;
6+
using Coverlet.Collector.Utilities.Interfaces;
7+
using Microsoft.VisualStudio.TestPlatform.ObjectModel.DataCollection;
8+
9+
namespace Coverlet.Collector.DataCollection
10+
{
11+
/// <summary>
12+
/// Manages coverage report attachments
13+
/// </summary>
14+
internal class AttachmentManager : IDisposable
15+
{
16+
private readonly DataCollectionSink _dataSink;
17+
private readonly TestPlatformEqtTrace _eqtTrace;
18+
private readonly TestPlatformLogger _logger;
19+
private readonly DataCollectionContext _dataCollectionContext;
20+
private readonly IFileHelper _fileHelper;
21+
private readonly IDirectoryHelper _directoryHelper;
22+
private readonly string _reportFileName;
23+
private readonly string _reportDirectory;
24+
25+
public AttachmentManager(DataCollectionSink dataSink, DataCollectionContext dataCollectionContext, TestPlatformLogger logger, TestPlatformEqtTrace eqtTrace, string reportFileName)
26+
: this(dataSink,
27+
dataCollectionContext,
28+
logger,
29+
eqtTrace,
30+
reportFileName,
31+
Guid.NewGuid().ToString(),
32+
new FileHelper(),
33+
new DirectoryHelper())
34+
{
35+
}
36+
37+
public AttachmentManager(DataCollectionSink dataSink, DataCollectionContext dataCollectionContext, TestPlatformLogger logger, TestPlatformEqtTrace eqtTrace, string reportFileName, string reportDirectoryName, IFileHelper fileHelper, IDirectoryHelper directoryHelper)
38+
{
39+
// Store input variabless
40+
_dataSink = dataSink;
41+
_dataCollectionContext = dataCollectionContext;
42+
_logger = logger;
43+
_eqtTrace = eqtTrace;
44+
_reportFileName = reportFileName;
45+
_fileHelper = fileHelper;
46+
_directoryHelper = directoryHelper;
47+
48+
// Report directory to store the coverage reports.
49+
_reportDirectory = Path.Combine(Path.GetTempPath(), reportDirectoryName);
50+
51+
// Register events
52+
_dataSink.SendFileCompleted += this.OnSendFileCompleted;
53+
}
54+
55+
/// <summary>
56+
/// Sends coverage report to test platform
57+
/// </summary>
58+
/// <param name="coverageReport">Coverage report</param>
59+
public void SendCoverageReport(string coverageReport)
60+
{
61+
// Save coverage report to file
62+
string coverageReportPath = this.SaveCoverageReport(coverageReport);
63+
64+
// Send coverage attachment to test platform.
65+
this.SendAttachment(coverageReportPath);
66+
}
67+
68+
/// <summary>
69+
/// Disposes attachment manager
70+
/// </summary>
71+
public void Dispose()
72+
{
73+
// Unregister events
74+
try
75+
{
76+
if (_dataSink != null)
77+
{
78+
_dataSink.SendFileCompleted -= this.OnSendFileCompleted;
79+
}
80+
this.CleanupReportDirectory();
81+
}
82+
catch (Exception ex)
83+
{
84+
_logger.LogWarning(ex.ToString());
85+
}
86+
}
87+
88+
/// <summary>
89+
/// Saves coverage report to file system
90+
/// </summary>
91+
/// <param name="report">Coverage report</param>
92+
/// <returns>Coverage report file path</returns>
93+
private string SaveCoverageReport(string report)
94+
{
95+
try
96+
{
97+
_directoryHelper.CreateDirectory(_reportDirectory);
98+
string filePath = Path.Combine(_reportDirectory, _reportFileName);
99+
_fileHelper.WriteAllText(filePath, report);
100+
_eqtTrace.Info("{0}: Saved coverage report to path: '{1}'", CoverletConstants.DataCollectorName, filePath);
101+
102+
return filePath;
103+
}
104+
catch (Exception ex)
105+
{
106+
string errorMessage = string.Format(Resources.FailedToSaveCoverageReport, CoverletConstants.DataCollectorName, _reportFileName, _reportDirectory);
107+
throw new CoverletDataCollectorException(errorMessage, ex);
108+
}
109+
}
110+
111+
/// <summary>
112+
/// SendFileCompleted event handler
113+
/// </summary>
114+
/// <param name="sender">Sender</param>
115+
/// <param name="e">Event args</param>
116+
public void OnSendFileCompleted(object sender, AsyncCompletedEventArgs e)
117+
{
118+
try
119+
{
120+
_eqtTrace.Verbose("{0}: SendFileCompleted received", CoverletConstants.DataCollectorName);
121+
this.CleanupReportDirectory();
122+
}
123+
catch (Exception ex)
124+
{
125+
_logger.LogWarning(ex.ToString());
126+
this.Dispose();
127+
}
128+
}
129+
130+
/// <summary>
131+
/// Sends attachment file to test platform
132+
/// </summary>
133+
/// <param name="attachmentPath">Attachment file path</param>
134+
private void SendAttachment(string attachmentPath)
135+
{
136+
if (_fileHelper.Exists(attachmentPath))
137+
{
138+
// Send coverage attachment to test platform.
139+
_eqtTrace.Verbose("{0}: Sending attachment to test platform", CoverletConstants.DataCollectorName);
140+
_dataSink.SendFileAsync(_dataCollectionContext, attachmentPath, false);
141+
}
142+
else
143+
{
144+
_eqtTrace.Warning("{0}: Attachment file does not exist", CoverletConstants.DataCollectorName);
145+
}
146+
}
147+
148+
/// <summary>
149+
/// Cleans up coverage report directory
150+
/// </summary>
151+
private void CleanupReportDirectory()
152+
{
153+
try
154+
{
155+
if (_directoryHelper.Exists(_reportDirectory))
156+
{
157+
_directoryHelper.Delete(_reportDirectory, true);
158+
_eqtTrace.Verbose("{0}: Deleted report directory: '{1}'", CoverletConstants.DataCollectorName, _reportDirectory);
159+
}
160+
}
161+
catch (Exception ex)
162+
{
163+
string errorMessage = string.Format(Resources.FailedToCleanupReportDirectory, CoverletConstants.DataCollectorName, _reportDirectory);
164+
throw new CoverletDataCollectorException(errorMessage, ex);
165+
}
166+
}
167+
}
168+
}
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
using System;
2+
using coverlet.collector.Resources;
3+
using Coverlet.Collector.Utilities;
4+
using Coverlet.Collector.Utilities.Interfaces;
5+
using Coverlet.Core;
6+
using Coverlet.Core.Logging;
7+
using Coverlet.Core.Reporters;
8+
9+
namespace Coverlet.Collector.DataCollection
10+
{
11+
/// <summary>
12+
/// Manages coverlet coverage
13+
/// </summary>
14+
internal class CoverageManager
15+
{
16+
private readonly Coverage _coverage;
17+
18+
private ICoverageWrapper _coverageWrapper;
19+
20+
public IReporter Reporter { get; }
21+
22+
public CoverageManager(CoverletSettings settings, TestPlatformEqtTrace eqtTrace, TestPlatformLogger logger, ICoverageWrapper coverageWrapper)
23+
: this(settings,
24+
new ReporterFactory(settings.ReportFormat).CreateReporter(),
25+
new CoverletLogger(eqtTrace, logger),
26+
coverageWrapper)
27+
{
28+
}
29+
30+
public CoverageManager(CoverletSettings settings, IReporter reporter, ILogger logger, ICoverageWrapper coverageWrapper)
31+
{
32+
// Store input vars
33+
Reporter = reporter;
34+
_coverageWrapper = coverageWrapper;
35+
36+
// Coverage object
37+
_coverage = _coverageWrapper.CreateCoverage(settings, logger);
38+
}
39+
40+
/// <summary>
41+
/// Instrument modules
42+
/// </summary>
43+
public void InstrumentModules()
44+
{
45+
try
46+
{
47+
// Instrument modules
48+
_coverageWrapper.PrepareModules(_coverage);
49+
}
50+
catch (Exception ex)
51+
{
52+
string errorMessage = string.Format(Resources.InstrumentationException, CoverletConstants.DataCollectorName);
53+
throw new CoverletDataCollectorException(errorMessage, ex);
54+
}
55+
}
56+
57+
/// <summary>
58+
/// Gets coverlet coverage report
59+
/// </summary>
60+
/// <returns>Coverage report</returns>
61+
public string GetCoverageReport()
62+
{
63+
// Get coverage result
64+
CoverageResult coverageResult = this.GetCoverageResult();
65+
66+
// Get coverage report in default format
67+
string coverageReport = this.GetCoverageReport(coverageResult);
68+
return coverageReport;
69+
}
70+
71+
/// <summary>
72+
/// Gets coverlet coverage result
73+
/// </summary>
74+
/// <returns>Coverage result</returns>
75+
private CoverageResult GetCoverageResult()
76+
{
77+
try
78+
{
79+
return _coverageWrapper.GetCoverageResult(_coverage);
80+
}
81+
catch (Exception ex)
82+
{
83+
string errorMessage = string.Format(Resources.CoverageResultException, CoverletConstants.DataCollectorName);
84+
throw new CoverletDataCollectorException(errorMessage, ex);
85+
}
86+
}
87+
88+
/// <summary>
89+
/// Gets coverage report from coverage result
90+
/// </summary>
91+
/// <param name="coverageResult">Coverage result</param>
92+
/// <returns>Coverage report</returns>
93+
private string GetCoverageReport(CoverageResult coverageResult)
94+
{
95+
try
96+
{
97+
return Reporter.Report(coverageResult);
98+
}
99+
catch (Exception ex)
100+
{
101+
string errorMessage = string.Format(Resources.CoverageReportException, CoverletConstants.DataCollectorName);
102+
throw new CoverletDataCollectorException(errorMessage, ex);
103+
}
104+
}
105+
}
106+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
using Coverlet.Collector.Utilities.Interfaces;
2+
using Coverlet.Core;
3+
using Coverlet.Core.Logging;
4+
5+
namespace Coverlet.Collector.DataCollection
6+
{
7+
/// <summary>
8+
/// Implementation for wrapping over Coverage class in coverlet.core
9+
/// </summary>
10+
internal class CoverageWrapper : ICoverageWrapper
11+
{
12+
/// <summary>
13+
/// Creates a coverage object from given coverlet settings
14+
/// </summary>
15+
/// <param name="settings">Coverlet settings</param>
16+
/// <param name="coverletLogger">Coverlet logger</param>
17+
/// <returns>Coverage object</returns>
18+
public Coverage CreateCoverage(CoverletSettings settings, ILogger coverletLogger)
19+
{
20+
return new Coverage(
21+
settings.TestModule,
22+
settings.IncludeFilters,
23+
settings.IncludeDirectories,
24+
settings.ExcludeFilters,
25+
settings.ExcludeSourceFiles,
26+
settings.ExcludeAttributes,
27+
settings.IncludeTestAssembly,
28+
settings.SingleHit,
29+
settings.MergeWith,
30+
settings.UseSourceLink,
31+
coverletLogger);
32+
}
33+
34+
/// <summary>
35+
/// Gets the coverage result from provided coverage object
36+
/// </summary>
37+
/// <param name="coverage">Coverage</param>
38+
/// <returns>The coverage result</returns>
39+
public CoverageResult GetCoverageResult(Coverage coverage)
40+
{
41+
return coverage.GetCoverageResult();
42+
}
43+
44+
/// <summary>
45+
/// Prepares modules for getting coverage.
46+
/// Wrapper over coverage.PrepareModules
47+
/// </summary>
48+
/// <param name="coverage"></param>
49+
public void PrepareModules(Coverage coverage)
50+
{
51+
coverage.PrepareModules();
52+
}
53+
}
54+
}

0 commit comments

Comments
 (0)