diff --git a/.editorconfig b/.editorconfig
index 3cfc4f441..85fec93f6 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -13,6 +13,8 @@ indent_style = space
indent_size = 4
trim_trailing_whitespace = true
+file_header_template = Copyright (c) Toni Solarin-Sodara\nLicensed under the MIT license. See LICENSE file in the project root for full license information.
+
# XML project files
[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}]
indent_size = 2
diff --git a/Documentation/Examples/.editorconfig b/Documentation/Examples/.editorconfig
new file mode 100644
index 000000000..d66ee0772
--- /dev/null
+++ b/Documentation/Examples/.editorconfig
@@ -0,0 +1,8 @@
+# top-most EditorConfig file
+# We don't want to import other EditorConfig files and we want
+# to ensure no rules are enabled for these asset source files.
+root = true
+
+[*.cs]
+# Default severity for all analyzer diagnostics
+dotnet_analyzer_diagnostic.severity = none
diff --git a/Documentation/Examples/MSBuild/DeterministicBuild/ClassLibrary1/Class1.cs b/Documentation/Examples/MSBuild/DeterministicBuild/ClassLibrary1/Class1.cs
index 289865e7b..dcb976188 100644
--- a/Documentation/Examples/MSBuild/DeterministicBuild/ClassLibrary1/Class1.cs
+++ b/Documentation/Examples/MSBuild/DeterministicBuild/ClassLibrary1/Class1.cs
@@ -1,8 +1,6 @@
-using System;
-
-namespace ClassLibrary1
+namespace ClassLibrary1
{
- public class Class1
+ public class Class1
{
public int Method()
{
diff --git a/Documentation/Examples/MSBuild/DeterministicBuild/ClassLibrary1/ClassLibrary1.csproj b/Documentation/Examples/MSBuild/DeterministicBuild/ClassLibrary1/ClassLibrary1.csproj
index 9f5c4f4ab..8271e5471 100644
--- a/Documentation/Examples/MSBuild/DeterministicBuild/ClassLibrary1/ClassLibrary1.csproj
+++ b/Documentation/Examples/MSBuild/DeterministicBuild/ClassLibrary1/ClassLibrary1.csproj
@@ -2,6 +2,7 @@
netstandard2.0
+ false
diff --git a/Documentation/Examples/MSBuild/DeterministicBuild/Directory.Build.props b/Documentation/Examples/MSBuild/DeterministicBuild/Directory.Build.props
index 5c27e11f6..34a4ddf95 100644
--- a/Documentation/Examples/MSBuild/DeterministicBuild/Directory.Build.props
+++ b/Documentation/Examples/MSBuild/DeterministicBuild/Directory.Build.props
@@ -8,6 +8,9 @@
-
+
+ all
+ runtime; build; native; contentfiles; analyzers
+
diff --git a/Documentation/Examples/MSBuild/DeterministicBuild/Directory.Build.targets b/Documentation/Examples/MSBuild/DeterministicBuild/Directory.Build.targets
index 95978e1e1..faf2349ba 100644
--- a/Documentation/Examples/MSBuild/DeterministicBuild/Directory.Build.targets
+++ b/Documentation/Examples/MSBuild/DeterministicBuild/Directory.Build.targets
@@ -1,4 +1,3 @@
-
-
+
diff --git a/Documentation/Examples/MSBuild/DeterministicBuild/XUnitTestProject1/XUnitTestProject1.csproj b/Documentation/Examples/MSBuild/DeterministicBuild/XUnitTestProject1/XUnitTestProject1.csproj
index f59a5b534..a7bac6432 100644
--- a/Documentation/Examples/MSBuild/DeterministicBuild/XUnitTestProject1/XUnitTestProject1.csproj
+++ b/Documentation/Examples/MSBuild/DeterministicBuild/XUnitTestProject1/XUnitTestProject1.csproj
@@ -3,6 +3,7 @@
net6.0
false
+ false
diff --git a/Documentation/Examples/MSBuild/MergeWith/ClassLibrary1/Class1.cs b/Documentation/Examples/MSBuild/MergeWith/ClassLibrary1/Class1.cs
index 289865e7b..dcb976188 100644
--- a/Documentation/Examples/MSBuild/MergeWith/ClassLibrary1/Class1.cs
+++ b/Documentation/Examples/MSBuild/MergeWith/ClassLibrary1/Class1.cs
@@ -1,8 +1,6 @@
-using System;
-
-namespace ClassLibrary1
+namespace ClassLibrary1
{
- public class Class1
+ public class Class1
{
public int Method()
{
diff --git a/Documentation/Examples/MSBuild/MergeWith/ClassLibrary2/Class2.cs b/Documentation/Examples/MSBuild/MergeWith/ClassLibrary2/Class2.cs
index aa93f5552..a2b5a7acc 100644
--- a/Documentation/Examples/MSBuild/MergeWith/ClassLibrary2/Class2.cs
+++ b/Documentation/Examples/MSBuild/MergeWith/ClassLibrary2/Class2.cs
@@ -1,8 +1,6 @@
-using System;
-
-namespace ClassLibrary2
+namespace ClassLibrary2
{
- public class Class2
+ public class Class2
{
public int Method()
{
diff --git a/Documentation/Examples/MSBuild/MergeWith/ClassLibrary3/Class3.cs b/Documentation/Examples/MSBuild/MergeWith/ClassLibrary3/Class3.cs
index 872291eb2..cfecc19cf 100644
--- a/Documentation/Examples/MSBuild/MergeWith/ClassLibrary3/Class3.cs
+++ b/Documentation/Examples/MSBuild/MergeWith/ClassLibrary3/Class3.cs
@@ -1,8 +1,6 @@
-using System;
-
-namespace ClassLibrary3
+namespace ClassLibrary3
{
- public class Class3
+ public class Class3
{
public int Method()
{
diff --git a/Documentation/Examples/MSBuild/MergeWith/XUnitTestProject1/UnitTest1.cs b/Documentation/Examples/MSBuild/MergeWith/XUnitTestProject1/UnitTest1.cs
index 5eeb5df3b..47655c8e7 100644
--- a/Documentation/Examples/MSBuild/MergeWith/XUnitTestProject1/UnitTest1.cs
+++ b/Documentation/Examples/MSBuild/MergeWith/XUnitTestProject1/UnitTest1.cs
@@ -1,9 +1,8 @@
-using System;
-using Xunit;
+using Xunit;
namespace XUnitTestProject1
{
- public class UnitTest1
+ public class UnitTest1
{
[Fact]
public void Test1()
diff --git a/Documentation/Examples/MSBuild/MergeWith/XUnitTestProject1/XUnitTestProject1.csproj b/Documentation/Examples/MSBuild/MergeWith/XUnitTestProject1/XUnitTestProject1.csproj
index e549327fa..7092bbf88 100644
--- a/Documentation/Examples/MSBuild/MergeWith/XUnitTestProject1/XUnitTestProject1.csproj
+++ b/Documentation/Examples/MSBuild/MergeWith/XUnitTestProject1/XUnitTestProject1.csproj
@@ -3,6 +3,7 @@
net6.0
false
+ false
diff --git a/Documentation/Examples/MSBuild/MergeWith/XUnitTestProject2/UnitTest2.cs b/Documentation/Examples/MSBuild/MergeWith/XUnitTestProject2/UnitTest2.cs
index c6ce4b13d..48a8448a2 100644
--- a/Documentation/Examples/MSBuild/MergeWith/XUnitTestProject2/UnitTest2.cs
+++ b/Documentation/Examples/MSBuild/MergeWith/XUnitTestProject2/UnitTest2.cs
@@ -1,9 +1,8 @@
-using System;
-using Xunit;
+using Xunit;
namespace XUnitTestProject2
{
- public class UnitTest2
+ public class UnitTest2
{
[Fact]
public void Test2()
diff --git a/Documentation/Examples/MSBuild/MergeWith/XUnitTestProject2/XUnitTestProject2.csproj b/Documentation/Examples/MSBuild/MergeWith/XUnitTestProject2/XUnitTestProject2.csproj
index be361474f..3af80f3d9 100644
--- a/Documentation/Examples/MSBuild/MergeWith/XUnitTestProject2/XUnitTestProject2.csproj
+++ b/Documentation/Examples/MSBuild/MergeWith/XUnitTestProject2/XUnitTestProject2.csproj
@@ -3,6 +3,7 @@
net6.0
false
+ false
diff --git a/Documentation/Examples/MSBuild/MergeWith/XUnitTestProject3/UnitTest3.cs b/Documentation/Examples/MSBuild/MergeWith/XUnitTestProject3/UnitTest3.cs
index 482d9ed81..34cb51c16 100644
--- a/Documentation/Examples/MSBuild/MergeWith/XUnitTestProject3/UnitTest3.cs
+++ b/Documentation/Examples/MSBuild/MergeWith/XUnitTestProject3/UnitTest3.cs
@@ -1,9 +1,8 @@
-using System;
-using Xunit;
+using Xunit;
namespace XUnitTestProject3
{
- public class UnitTest3
+ public class UnitTest3
{
[Fact]
public void Test3()
diff --git a/Documentation/Examples/MSBuild/MergeWith/XUnitTestProject3/XUnitTestProject3.csproj b/Documentation/Examples/MSBuild/MergeWith/XUnitTestProject3/XUnitTestProject3.csproj
index c622ecd0a..668ef16a0 100644
--- a/Documentation/Examples/MSBuild/MergeWith/XUnitTestProject3/XUnitTestProject3.csproj
+++ b/Documentation/Examples/MSBuild/MergeWith/XUnitTestProject3/XUnitTestProject3.csproj
@@ -3,6 +3,7 @@
net6.0
false
+ false
diff --git a/Documentation/Examples/VSTest/DeterministicBuild/ClassLibrary1/ClassLibrary1.csproj b/Documentation/Examples/VSTest/DeterministicBuild/ClassLibrary1/ClassLibrary1.csproj
index 9f5c4f4ab..8271e5471 100644
--- a/Documentation/Examples/VSTest/DeterministicBuild/ClassLibrary1/ClassLibrary1.csproj
+++ b/Documentation/Examples/VSTest/DeterministicBuild/ClassLibrary1/ClassLibrary1.csproj
@@ -2,6 +2,7 @@
netstandard2.0
+ false
diff --git a/Documentation/Examples/VSTest/DeterministicBuild/XUnitTestProject1/XUnitTestProject1.csproj b/Documentation/Examples/VSTest/DeterministicBuild/XUnitTestProject1/XUnitTestProject1.csproj
index 642b38552..7f5fd73b3 100644
--- a/Documentation/Examples/VSTest/DeterministicBuild/XUnitTestProject1/XUnitTestProject1.csproj
+++ b/Documentation/Examples/VSTest/DeterministicBuild/XUnitTestProject1/XUnitTestProject1.csproj
@@ -1,4 +1,4 @@
-
+
net6.0
diff --git a/Documentation/Examples/VSTest/HelloWorld/ClassLibrary1/Class1.cs b/Documentation/Examples/VSTest/HelloWorld/ClassLibrary1/Class1.cs
index 289865e7b..dcb976188 100644
--- a/Documentation/Examples/VSTest/HelloWorld/ClassLibrary1/Class1.cs
+++ b/Documentation/Examples/VSTest/HelloWorld/ClassLibrary1/Class1.cs
@@ -1,8 +1,6 @@
-using System;
-
-namespace ClassLibrary1
+namespace ClassLibrary1
{
- public class Class1
+ public class Class1
{
public int Method()
{
diff --git a/Documentation/Examples/VSTest/HelloWorld/ClassLibrary1/ClassLibrary1.csproj b/Documentation/Examples/VSTest/HelloWorld/ClassLibrary1/ClassLibrary1.csproj
index 9f5c4f4ab..8271e5471 100644
--- a/Documentation/Examples/VSTest/HelloWorld/ClassLibrary1/ClassLibrary1.csproj
+++ b/Documentation/Examples/VSTest/HelloWorld/ClassLibrary1/ClassLibrary1.csproj
@@ -2,6 +2,7 @@
netstandard2.0
+ false
diff --git a/Documentation/Examples/VSTest/HelloWorld/XUnitTestProject1/runsettings.xml b/Documentation/Examples/VSTest/HelloWorld/XUnitTestProject1/.runsettings
similarity index 100%
rename from Documentation/Examples/VSTest/HelloWorld/XUnitTestProject1/runsettings.xml
rename to Documentation/Examples/VSTest/HelloWorld/XUnitTestProject1/.runsettings
diff --git a/Documentation/Examples/VSTest/HelloWorld/XUnitTestProject1/UnitTest1.cs b/Documentation/Examples/VSTest/HelloWorld/XUnitTestProject1/UnitTest1.cs
index 5eeb5df3b..47655c8e7 100644
--- a/Documentation/Examples/VSTest/HelloWorld/XUnitTestProject1/UnitTest1.cs
+++ b/Documentation/Examples/VSTest/HelloWorld/XUnitTestProject1/UnitTest1.cs
@@ -1,9 +1,8 @@
-using System;
-using Xunit;
+using Xunit;
namespace XUnitTestProject1
{
- public class UnitTest1
+ public class UnitTest1
{
[Fact]
public void Test1()
diff --git a/Documentation/Examples/VSTest/HelloWorld/XUnitTestProject1/XUnitTestProject1.csproj b/Documentation/Examples/VSTest/HelloWorld/XUnitTestProject1/XUnitTestProject1.csproj
index 87be69a78..2dee501a6 100644
--- a/Documentation/Examples/VSTest/HelloWorld/XUnitTestProject1/XUnitTestProject1.csproj
+++ b/Documentation/Examples/VSTest/HelloWorld/XUnitTestProject1/XUnitTestProject1.csproj
@@ -4,6 +4,7 @@
net6.0
false
false
+ $(MSBuildThisFileDirectory).runsettings
diff --git a/src/coverlet.collector/DataCollection/AttachmentManager.cs b/src/coverlet.collector/DataCollection/AttachmentManager.cs
index 8259f71f3..9a4a68786 100644
--- a/src/coverlet.collector/DataCollection/AttachmentManager.cs
+++ b/src/coverlet.collector/DataCollection/AttachmentManager.cs
@@ -11,166 +11,166 @@
namespace Coverlet.Collector.DataCollection
{
- ///
- /// Manages coverage report attachments
- ///
- 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 ICountDownEvent _countDownEvent;
- private readonly string _reportDirectory;
+ ///
+ /// Manages coverage report attachments
+ ///
+ 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 ICountDownEvent _countDownEvent;
+ private readonly string _reportDirectory;
- public AttachmentManager(DataCollectionSink dataSink, DataCollectionContext dataCollectionContext, TestPlatformLogger logger, TestPlatformEqtTrace eqtTrace, ICountDownEvent countDownEvent)
- : this(dataSink,
- dataCollectionContext,
- logger,
- eqtTrace,
- Guid.NewGuid().ToString(),
- new FileHelper(),
- new DirectoryHelper(),
- countDownEvent)
- {
- }
+ public AttachmentManager(DataCollectionSink dataSink, DataCollectionContext dataCollectionContext, TestPlatformLogger logger, TestPlatformEqtTrace eqtTrace, ICountDownEvent countDownEvent)
+ : this(dataSink,
+ dataCollectionContext,
+ logger,
+ eqtTrace,
+ Guid.NewGuid().ToString(),
+ new FileHelper(),
+ new DirectoryHelper(),
+ countDownEvent)
+ {
+ }
- public AttachmentManager(DataCollectionSink dataSink, DataCollectionContext dataCollectionContext, TestPlatformLogger logger, TestPlatformEqtTrace eqtTrace, string reportDirectoryName, IFileHelper fileHelper, IDirectoryHelper directoryHelper, ICountDownEvent countDownEvent)
- {
- // Store input variabless
- _dataSink = dataSink;
- _dataCollectionContext = dataCollectionContext;
- _logger = logger;
- _eqtTrace = eqtTrace;
- _fileHelper = fileHelper;
- _directoryHelper = directoryHelper;
- _countDownEvent = countDownEvent;
+ public AttachmentManager(DataCollectionSink dataSink, DataCollectionContext dataCollectionContext, TestPlatformLogger logger, TestPlatformEqtTrace eqtTrace, string reportDirectoryName, IFileHelper fileHelper, IDirectoryHelper directoryHelper, ICountDownEvent countDownEvent)
+ {
+ // Store input variables
+ _dataSink = dataSink;
+ _dataCollectionContext = dataCollectionContext;
+ _logger = logger;
+ _eqtTrace = eqtTrace;
+ _fileHelper = fileHelper;
+ _directoryHelper = directoryHelper;
+ _countDownEvent = countDownEvent;
- // Report directory to store the coverage reports.
- _reportDirectory = Path.Combine(Path.GetTempPath(), reportDirectoryName);
+ // Report directory to store the coverage reports.
+ _reportDirectory = Path.Combine(Path.GetTempPath(), reportDirectoryName);
- // Register events
- _dataSink.SendFileCompleted += OnSendFileCompleted;
- }
+ // Register events
+ _dataSink.SendFileCompleted += OnSendFileCompleted;
+ }
- ///
- /// Sends coverage report to test platform
- ///
- /// Coverage report
- /// Coverage report file name
- public void SendCoverageReport(string coverageReport, string coverageReportFileName)
- {
- // Save coverage report to file
- string coverageReportPath = SaveCoverageReport(coverageReport, coverageReportFileName);
+ ///
+ /// Sends coverage report to test platform
+ ///
+ /// Coverage report
+ /// Coverage report file name
+ public void SendCoverageReport(string coverageReport, string coverageReportFileName)
+ {
+ // Save coverage report to file
+ string coverageReportPath = SaveCoverageReport(coverageReport, coverageReportFileName);
- // Send coverage attachment to test platform.
- SendAttachment(coverageReportPath);
- }
+ // Send coverage attachment to test platform.
+ SendAttachment(coverageReportPath);
+ }
- ///
- /// Disposes attachment manager
- ///
- public void Dispose()
+ ///
+ /// Disposes attachment manager
+ ///
+ public void Dispose()
+ {
+ // Unregister events
+ try
+ {
+ _countDownEvent.Wait();
+ if (_dataSink != null)
{
- // Unregister events
- try
- {
- _countDownEvent.Wait();
- if (_dataSink != null)
- {
- _dataSink.SendFileCompleted -= OnSendFileCompleted;
- }
- CleanupReportDirectory();
- }
- catch (Exception ex)
- {
- _logger.LogWarning(ex.ToString());
- }
+ _dataSink.SendFileCompleted -= OnSendFileCompleted;
}
+ CleanupReportDirectory();
+ }
+ catch (Exception ex)
+ {
+ _logger.LogWarning(ex.ToString());
+ }
+ }
- ///
- /// Saves coverage report to file system
- ///
- /// Coverage report
- /// Coverage report file name
- /// Coverage report file path
- private string SaveCoverageReport(string report, string reportFileName)
- {
- try
- {
- _directoryHelper.CreateDirectory(_reportDirectory);
- string filePath = Path.Combine(_reportDirectory, reportFileName);
- _fileHelper.WriteAllText(filePath, report);
- _eqtTrace.Info("{0}: Saved coverage report to path: '{1}'", CoverletConstants.DataCollectorName, filePath);
+ ///
+ /// Saves coverage report to file system
+ ///
+ /// Coverage report
+ /// Coverage report file name
+ /// Coverage report file path
+ private string SaveCoverageReport(string report, string reportFileName)
+ {
+ try
+ {
+ _directoryHelper.CreateDirectory(_reportDirectory);
+ string filePath = Path.Combine(_reportDirectory, reportFileName);
+ _fileHelper.WriteAllText(filePath, report);
+ _eqtTrace.Info("{0}: Saved coverage report to path: '{1}'", CoverletConstants.DataCollectorName, filePath);
- return filePath;
- }
- catch (Exception ex)
- {
- string errorMessage = string.Format(Resources.FailedToSaveCoverageReport, CoverletConstants.DataCollectorName, reportFileName, _reportDirectory);
- throw new CoverletDataCollectorException(errorMessage, ex);
- }
- }
+ return filePath;
+ }
+ catch (Exception ex)
+ {
+ string errorMessage = string.Format(Resources.FailedToSaveCoverageReport, CoverletConstants.DataCollectorName, reportFileName, _reportDirectory);
+ throw new CoverletDataCollectorException(errorMessage, ex);
+ }
+ }
- ///
- /// SendFileCompleted event handler
- ///
- /// Sender
- /// Event args
- public void OnSendFileCompleted(object sender, AsyncCompletedEventArgs e)
- {
- try
- {
- _eqtTrace.Verbose("{0}: SendFileCompleted received", CoverletConstants.DataCollectorName);
- }
- catch (Exception ex)
- {
- _logger.LogWarning(ex.ToString());
- }
- finally
- {
- _countDownEvent.Signal();
- }
- }
+ ///
+ /// SendFileCompleted event handler
+ ///
+ /// Sender
+ /// Event args
+ public void OnSendFileCompleted(object sender, AsyncCompletedEventArgs e)
+ {
+ try
+ {
+ _eqtTrace.Verbose("{0}: SendFileCompleted received", CoverletConstants.DataCollectorName);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogWarning(ex.ToString());
+ }
+ finally
+ {
+ _countDownEvent.Signal();
+ }
+ }
- ///
- /// Sends attachment file to test platform
- ///
- /// Attachment file path
- private void SendAttachment(string attachmentPath)
- {
- if (_fileHelper.Exists(attachmentPath))
- {
- // Send coverage attachment to test platform.
- _eqtTrace.Verbose("{0}: Sending attachment to test platform", CoverletConstants.DataCollectorName);
- _dataSink.SendFileAsync(_dataCollectionContext, attachmentPath, false);
- }
- else
- {
- _eqtTrace.Warning("{0}: Attachment file does not exist", CoverletConstants.DataCollectorName);
- }
- }
+ ///
+ /// Sends attachment file to test platform
+ ///
+ /// Attachment file path
+ private void SendAttachment(string attachmentPath)
+ {
+ if (_fileHelper.Exists(attachmentPath))
+ {
+ // Send coverage attachment to test platform.
+ _eqtTrace.Verbose("{0}: Sending attachment to test platform", CoverletConstants.DataCollectorName);
+ _dataSink.SendFileAsync(_dataCollectionContext, attachmentPath, false);
+ }
+ else
+ {
+ _eqtTrace.Warning("{0}: Attachment file does not exist", CoverletConstants.DataCollectorName);
+ }
+ }
- ///
- /// Cleans up coverage report directory
- ///
- private void CleanupReportDirectory()
+ ///
+ /// Cleans up coverage report directory
+ ///
+ private void CleanupReportDirectory()
+ {
+ try
+ {
+ if (_directoryHelper.Exists(_reportDirectory))
{
- try
- {
- if (_directoryHelper.Exists(_reportDirectory))
- {
- _directoryHelper.Delete(_reportDirectory, true);
- _eqtTrace.Verbose("{0}: Deleted report directory: '{1}'", CoverletConstants.DataCollectorName, _reportDirectory);
- }
- }
- catch (Exception ex)
- {
- string errorMessage = string.Format(Resources.FailedToCleanupReportDirectory, CoverletConstants.DataCollectorName, _reportDirectory);
- throw new CoverletDataCollectorException(errorMessage, ex);
- }
+ _directoryHelper.Delete(_reportDirectory, true);
+ _eqtTrace.Verbose("{0}: Deleted report directory: '{1}'", CoverletConstants.DataCollectorName, _reportDirectory);
}
+ }
+ catch (Exception ex)
+ {
+ string errorMessage = string.Format(Resources.FailedToCleanupReportDirectory, CoverletConstants.DataCollectorName, _reportDirectory);
+ throw new CoverletDataCollectorException(errorMessage, ex);
+ }
}
+ }
}
diff --git a/src/coverlet.collector/DataCollection/CoverageManager.cs b/src/coverlet.collector/DataCollection/CoverageManager.cs
index 89ec41eb1..d6f6052c8 100644
--- a/src/coverlet.collector/DataCollection/CoverageManager.cs
+++ b/src/coverlet.collector/DataCollection/CoverageManager.cs
@@ -14,109 +14,109 @@
namespace Coverlet.Collector.DataCollection
{
- ///
- /// Manages coverlet coverage
- ///
- internal class CoverageManager
- {
- private readonly Coverage _coverage;
- private readonly ICoverageWrapper _coverageWrapper;
- private readonly ISourceRootTranslator _sourceRootTranslator;
- public IReporter[] Reporters { get; }
+ ///
+ /// Manages coverlet coverage
+ ///
+ internal class CoverageManager
+ {
+ private readonly Coverage _coverage;
+ private readonly ICoverageWrapper _coverageWrapper;
+ private readonly ISourceRootTranslator _sourceRootTranslator;
+ public IReporter[] Reporters { get; }
- public CoverageManager(CoverletSettings settings, TestPlatformEqtTrace eqtTrace, TestPlatformLogger logger, ICoverageWrapper coverageWrapper,
- IInstrumentationHelper instrumentationHelper, IFileSystem fileSystem, ISourceRootTranslator sourceRootTranslator, ICecilSymbolHelper cecilSymbolHelper)
- : this(settings,
- settings.ReportFormats.Select(format =>
- {
- var reporterFactory = new ReporterFactory(format);
- if (!reporterFactory.IsValidFormat())
- {
- eqtTrace.Warning($"Invalid report format '{format}'");
- return null;
- }
- else
- {
- return reporterFactory.CreateReporter();
- }
- }).Where(r => r != null).ToArray(),
- new CoverletLogger(eqtTrace, logger),
- coverageWrapper, instrumentationHelper, fileSystem, sourceRootTranslator, cecilSymbolHelper)
+ public CoverageManager(CoverletSettings settings, TestPlatformEqtTrace eqtTrace, TestPlatformLogger logger, ICoverageWrapper coverageWrapper,
+ IInstrumentationHelper instrumentationHelper, IFileSystem fileSystem, ISourceRootTranslator sourceRootTranslator, ICecilSymbolHelper cecilSymbolHelper)
+ : this(settings,
+ settings.ReportFormats.Select(format =>
{
- }
+ var reporterFactory = new ReporterFactory(format);
+ if (!reporterFactory.IsValidFormat())
+ {
+ eqtTrace.Warning($"Invalid report format '{format}'");
+ return null;
+ }
+ else
+ {
+ return reporterFactory.CreateReporter();
+ }
+ }).Where(r => r != null).ToArray(),
+ new CoverletLogger(eqtTrace, logger),
+ coverageWrapper, instrumentationHelper, fileSystem, sourceRootTranslator, cecilSymbolHelper)
+ {
+ }
- public CoverageManager(CoverletSettings settings, IReporter[] reporters, ILogger logger, ICoverageWrapper coverageWrapper,
- IInstrumentationHelper instrumentationHelper, IFileSystem fileSystem, ISourceRootTranslator sourceRootTranslator, ICecilSymbolHelper cecilSymbolHelper)
- {
- // Store input vars
- Reporters = reporters;
- _coverageWrapper = coverageWrapper;
- _sourceRootTranslator = sourceRootTranslator;
- // Coverage object
- _coverage = _coverageWrapper.CreateCoverage(settings, logger, instrumentationHelper, fileSystem, sourceRootTranslator, cecilSymbolHelper);
- }
+ public CoverageManager(CoverletSettings settings, IReporter[] reporters, ILogger logger, ICoverageWrapper coverageWrapper,
+ IInstrumentationHelper instrumentationHelper, IFileSystem fileSystem, ISourceRootTranslator sourceRootTranslator, ICecilSymbolHelper cecilSymbolHelper)
+ {
+ // Store input vars
+ Reporters = reporters;
+ _coverageWrapper = coverageWrapper;
+ _sourceRootTranslator = sourceRootTranslator;
+ // Coverage object
+ _coverage = _coverageWrapper.CreateCoverage(settings, logger, instrumentationHelper, fileSystem, sourceRootTranslator, cecilSymbolHelper);
+ }
- ///
- /// Instrument modules
- ///
- public void InstrumentModules()
- {
- try
- {
- // Instrument modules
- _coverageWrapper.PrepareModules(_coverage);
- }
- catch (Exception ex)
- {
- string errorMessage = string.Format(Resources.InstrumentationException, CoverletConstants.DataCollectorName);
- throw new CoverletDataCollectorException(errorMessage, ex);
- }
- }
+ ///
+ /// Instrument modules
+ ///
+ public void InstrumentModules()
+ {
+ try
+ {
+ // Instrument modules
+ _coverageWrapper.PrepareModules(_coverage);
+ }
+ catch (Exception ex)
+ {
+ string errorMessage = string.Format(Resources.InstrumentationException, CoverletConstants.DataCollectorName);
+ throw new CoverletDataCollectorException(errorMessage, ex);
+ }
+ }
- ///
- /// Gets coverlet coverage reports
- ///
- /// Coverage reports
- public IEnumerable<(string report, string fileName)> GetCoverageReports()
- {
- // Get coverage result
- CoverageResult coverageResult = GetCoverageResult();
- return GetCoverageReports(coverageResult);
- }
+ ///
+ /// Gets coverlet coverage reports
+ ///
+ /// Coverage reports
+ public IEnumerable<(string report, string fileName)> GetCoverageReports()
+ {
+ // Get coverage result
+ CoverageResult coverageResult = GetCoverageResult();
+ return GetCoverageReports(coverageResult);
+ }
- ///
- /// Gets coverlet coverage result
- ///
- /// Coverage result
- private CoverageResult GetCoverageResult()
- {
- try
- {
- return _coverageWrapper.GetCoverageResult(_coverage);
- }
- catch (Exception ex)
- {
- string errorMessage = string.Format(Resources.CoverageResultException, CoverletConstants.DataCollectorName);
- throw new CoverletDataCollectorException(errorMessage, ex);
- }
- }
+ ///
+ /// Gets coverlet coverage result
+ ///
+ /// Coverage result
+ private CoverageResult GetCoverageResult()
+ {
+ try
+ {
+ return _coverageWrapper.GetCoverageResult(_coverage);
+ }
+ catch (Exception ex)
+ {
+ string errorMessage = string.Format(Resources.CoverageResultException, CoverletConstants.DataCollectorName);
+ throw new CoverletDataCollectorException(errorMessage, ex);
+ }
+ }
- ///
- /// Gets coverage reports from coverage result
- ///
- /// Coverage result
- /// Coverage reports
- private IEnumerable<(string report, string fileName)> GetCoverageReports(CoverageResult coverageResult)
- {
- try
- {
- return Reporters.Select(reporter => (reporter.Report(coverageResult, _sourceRootTranslator), Path.ChangeExtension(CoverletConstants.DefaultFileName, reporter.Extension)));
- }
- catch (Exception ex)
- {
- string errorMessage = string.Format(Resources.CoverageReportException, CoverletConstants.DataCollectorName);
- throw new CoverletDataCollectorException(errorMessage, ex);
- }
- }
+ ///
+ /// Gets coverage reports from coverage result
+ ///
+ /// Coverage result
+ /// Coverage reports
+ private IEnumerable<(string report, string fileName)> GetCoverageReports(CoverageResult coverageResult)
+ {
+ try
+ {
+ return Reporters.Select(reporter => (reporter.Report(coverageResult, _sourceRootTranslator), Path.ChangeExtension(CoverletConstants.DefaultFileName, reporter.Extension)));
+ }
+ catch (Exception ex)
+ {
+ string errorMessage = string.Format(Resources.CoverageReportException, CoverletConstants.DataCollectorName);
+ throw new CoverletDataCollectorException(errorMessage, ex);
+ }
}
+ }
}
diff --git a/src/coverlet.collector/DataCollection/CoverageWrapper.cs b/src/coverlet.collector/DataCollection/CoverageWrapper.cs
index ffd7d8a41..4e3f5a729 100644
--- a/src/coverlet.collector/DataCollection/CoverageWrapper.cs
+++ b/src/coverlet.collector/DataCollection/CoverageWrapper.cs
@@ -7,68 +7,68 @@
namespace Coverlet.Collector.DataCollection
{
+ ///
+ /// Implementation for wrapping over Coverage class in coverlet.core
+ ///
+ internal class CoverageWrapper : ICoverageWrapper
+ {
///
- /// Implementation for wrapping over Coverage class in coverlet.core
+ /// Creates a coverage object from given coverlet settings
///
- internal class CoverageWrapper : ICoverageWrapper
+ /// Coverlet settings
+ /// Coverlet logger
+ ///
+ ///
+ ///
+ ///
+ /// Coverage object
+ public Coverage CreateCoverage(CoverletSettings settings, ILogger coverletLogger, IInstrumentationHelper instrumentationHelper, IFileSystem fileSystem, ISourceRootTranslator sourceRootTranslator, ICecilSymbolHelper cecilSymbolHelper)
{
- ///
- /// Creates a coverage object from given coverlet settings
- ///
- /// Coverlet settings
- /// Coverlet logger
- ///
- ///
- ///
- ///
- /// Coverage object
- public Coverage CreateCoverage(CoverletSettings settings, ILogger coverletLogger, IInstrumentationHelper instrumentationHelper, IFileSystem fileSystem, ISourceRootTranslator sourceRootTranslator, ICecilSymbolHelper cecilSymbolHelper)
- {
- CoverageParameters parameters = new()
- {
- IncludeFilters = settings.IncludeFilters,
- IncludeDirectories = settings.IncludeDirectories,
- ExcludeFilters = settings.ExcludeFilters,
- ExcludedSourceFiles = settings.ExcludeSourceFiles,
- ExcludeAttributes = settings.ExcludeAttributes,
- IncludeTestAssembly = settings.IncludeTestAssembly,
- SingleHit = settings.SingleHit,
- MergeWith = settings.MergeWith,
- UseSourceLink = settings.UseSourceLink,
- SkipAutoProps = settings.SkipAutoProps,
- DoesNotReturnAttributes = settings.DoesNotReturnAttributes,
- DeterministicReport = settings.DeterministicReport,
- ExcludeAssembliesWithoutSources = settings.ExcludeAssembliesWithoutSources
- };
+ CoverageParameters parameters = new()
+ {
+ IncludeFilters = settings.IncludeFilters,
+ IncludeDirectories = settings.IncludeDirectories,
+ ExcludeFilters = settings.ExcludeFilters,
+ ExcludedSourceFiles = settings.ExcludeSourceFiles,
+ ExcludeAttributes = settings.ExcludeAttributes,
+ IncludeTestAssembly = settings.IncludeTestAssembly,
+ SingleHit = settings.SingleHit,
+ MergeWith = settings.MergeWith,
+ UseSourceLink = settings.UseSourceLink,
+ SkipAutoProps = settings.SkipAutoProps,
+ DoesNotReturnAttributes = settings.DoesNotReturnAttributes,
+ DeterministicReport = settings.DeterministicReport,
+ ExcludeAssembliesWithoutSources = settings.ExcludeAssembliesWithoutSources
+ };
- return new Coverage(
- settings.TestModule,
- parameters,
- coverletLogger,
- instrumentationHelper,
- fileSystem,
- sourceRootTranslator,
- cecilSymbolHelper);
- }
+ return new Coverage(
+ settings.TestModule,
+ parameters,
+ coverletLogger,
+ instrumentationHelper,
+ fileSystem,
+ sourceRootTranslator,
+ cecilSymbolHelper);
+ }
- ///
- /// Gets the coverage result from provided coverage object
- ///
- /// Coverage
- /// The coverage result
- public CoverageResult GetCoverageResult(Coverage coverage)
- {
- return coverage.GetCoverageResult();
- }
+ ///
+ /// Gets the coverage result from provided coverage object
+ ///
+ /// Coverage
+ /// The coverage result
+ public CoverageResult GetCoverageResult(Coverage coverage)
+ {
+ return coverage.GetCoverageResult();
+ }
- ///
- /// Prepares modules for getting coverage.
- /// Wrapper over coverage.PrepareModules
- ///
- ///
- public void PrepareModules(Coverage coverage)
- {
- coverage.PrepareModules();
- }
+ ///
+ /// Prepares modules for getting coverage.
+ /// Wrapper over coverage.PrepareModules
+ ///
+ ///
+ public void PrepareModules(Coverage coverage)
+ {
+ coverage.PrepareModules();
}
+ }
}
diff --git a/src/coverlet.collector/DataCollection/CoverletCoverageCollector.cs b/src/coverlet.collector/DataCollection/CoverletCoverageCollector.cs
index d40a02e86..c95ba217b 100644
--- a/src/coverlet.collector/DataCollection/CoverletCoverageCollector.cs
+++ b/src/coverlet.collector/DataCollection/CoverletCoverageCollector.cs
@@ -16,223 +16,223 @@
namespace Coverlet.Collector.DataCollection
{
+ ///
+ /// Coverlet coverage out-proc data collector.
+ ///
+ [DataCollectorTypeUri(CoverletConstants.DefaultUri)]
+ [DataCollectorFriendlyName(CoverletConstants.FriendlyName)]
+ public class CoverletCoverageCollector : DataCollector
+ {
+ private readonly TestPlatformEqtTrace _eqtTrace;
+ private readonly ICoverageWrapper _coverageWrapper;
+ private readonly ICountDownEventFactory _countDownEventFactory;
+ private readonly Func _serviceCollectionFactory;
+
+ private DataCollectionEvents _events;
+ private TestPlatformLogger _logger;
+ private XmlElement _configurationElement;
+ private DataCollectionSink _dataSink;
+ private DataCollectionContext _dataCollectionContext;
+ private CoverageManager _coverageManager;
+ private IServiceProvider _serviceProvider;
+
+ public CoverletCoverageCollector() : this(new TestPlatformEqtTrace(), new CoverageWrapper(), new CollectorCountdownEventFactory(), GetDefaultServiceCollection)
+ {
+ }
+
+ internal CoverletCoverageCollector(TestPlatformEqtTrace eqtTrace, ICoverageWrapper coverageWrapper, ICountDownEventFactory countDownEventFactory, Func serviceCollectionFactory) : base()
+ {
+ _eqtTrace = eqtTrace;
+ _coverageWrapper = coverageWrapper;
+ _countDownEventFactory = countDownEventFactory;
+ _serviceCollectionFactory = serviceCollectionFactory;
+ }
+
+ private void AttachDebugger()
+ {
+ if (int.TryParse(Environment.GetEnvironmentVariable("COVERLET_DATACOLLECTOR_OUTOFPROC_DEBUG"), out int result) && result == 1)
+ {
+ Debugger.Launch();
+ Debugger.Break();
+ }
+ }
+
///
- /// Coverlet coverage out-proc data collector.
+ /// Initializes data collector
///
- [DataCollectorTypeUri(CoverletConstants.DefaultUri)]
- [DataCollectorFriendlyName(CoverletConstants.FriendlyName)]
- public class CoverletCoverageCollector : DataCollector
+ /// Configuration element
+ /// Events to register on
+ /// Data sink to send attachments to test platform
+ /// Test platform logger
+ /// Environment context
+ public override void Initialize(
+ XmlElement configurationElement,
+ DataCollectionEvents events,
+ DataCollectionSink dataSink,
+ DataCollectionLogger logger,
+ DataCollectionEnvironmentContext environmentContext)
{
- private readonly TestPlatformEqtTrace _eqtTrace;
- private readonly ICoverageWrapper _coverageWrapper;
- private readonly ICountDownEventFactory _countDownEventFactory;
- private readonly Func _serviceCollectionFactory;
-
- private DataCollectionEvents _events;
- private TestPlatformLogger _logger;
- private XmlElement _configurationElement;
- private DataCollectionSink _dataSink;
- private DataCollectionContext _dataCollectionContext;
- private CoverageManager _coverageManager;
- private IServiceProvider _serviceProvider;
-
- public CoverletCoverageCollector() : this(new TestPlatformEqtTrace(), new CoverageWrapper(), new CollectorCountdownEventFactory(), GetDefaultServiceCollection)
- {
- }
- internal CoverletCoverageCollector(TestPlatformEqtTrace eqtTrace, ICoverageWrapper coverageWrapper, ICountDownEventFactory countDownEventFactory, Func serviceCollectionFactory) : base()
- {
- _eqtTrace = eqtTrace;
- _coverageWrapper = coverageWrapper;
- _countDownEventFactory = countDownEventFactory;
- _serviceCollectionFactory = serviceCollectionFactory;
- }
+ AttachDebugger();
- private void AttachDebugger()
- {
- if (int.TryParse(Environment.GetEnvironmentVariable("COVERLET_DATACOLLECTOR_OUTOFPROC_DEBUG"), out int result) && result == 1)
- {
- Debugger.Launch();
- Debugger.Break();
- }
- }
+ if (_eqtTrace.IsInfoEnabled)
+ {
+ _eqtTrace.Info("Initializing {0} with configuration: '{1}'", CoverletConstants.DataCollectorName, configurationElement?.OuterXml);
+ }
- ///
- /// Initializes data collector
- ///
- /// Configuration element
- /// Events to register on
- /// Data sink to send attachments to test platform
- /// Test platform logger
- /// Environment context
- public override void Initialize(
- XmlElement configurationElement,
- DataCollectionEvents events,
- DataCollectionSink dataSink,
- DataCollectionLogger logger,
- DataCollectionEnvironmentContext environmentContext)
- {
+ // Store input variables
+ _events = events;
+ _configurationElement = configurationElement;
+ _dataSink = dataSink;
+ _dataCollectionContext = environmentContext.SessionDataCollectionContext;
+ _logger = new TestPlatformLogger(logger, _dataCollectionContext);
- AttachDebugger();
+ // Register events
+ _events.SessionStart += OnSessionStart;
+ _events.SessionEnd += OnSessionEnd;
+ }
- if (_eqtTrace.IsInfoEnabled)
- {
- _eqtTrace.Info("Initializing {0} with configuration: '{1}'", CoverletConstants.DataCollectorName, configurationElement?.OuterXml);
- }
+ ///
+ /// Disposes the data collector
+ ///
+ /// Disposing flag
+ protected override void Dispose(bool disposing)
+ {
+ _eqtTrace.Verbose("{0}: Disposing", CoverletConstants.DataCollectorName);
- // Store input variables
- _events = events;
- _configurationElement = configurationElement;
- _dataSink = dataSink;
- _dataCollectionContext = environmentContext.SessionDataCollectionContext;
- _logger = new TestPlatformLogger(logger, _dataCollectionContext);
+ // Unregister events
+ if (_events != null)
+ {
+ _events.SessionStart -= OnSessionStart;
+ _events.SessionEnd -= OnSessionEnd;
+ }
- // Register events
- _events.SessionStart += OnSessionStart;
- _events.SessionEnd += OnSessionEnd;
- }
+ // Remove vars
+ _events = null;
+ _dataSink = null;
+ _coverageManager = null;
- ///
- /// Disposes the data collector
- ///
- /// Disposing flag
- protected override void Dispose(bool disposing)
- {
- _eqtTrace.Verbose("{0}: Disposing", CoverletConstants.DataCollectorName);
+ base.Dispose(disposing);
+ }
- // Unregister events
- if (_events != null)
- {
- _events.SessionStart -= OnSessionStart;
- _events.SessionEnd -= OnSessionEnd;
- }
+ ///
+ /// SessionStart event handler
+ ///
+ /// Sender
+ /// Event args
+ private void OnSessionStart(object sender, SessionStartEventArgs sessionStartEventArgs)
+ {
+ _eqtTrace.Verbose("{0}: SessionStart received", CoverletConstants.DataCollectorName);
+
+ try
+ {
+ // Get coverlet settings
+ IEnumerable testModules = GetTestModules(sessionStartEventArgs);
+ var coverletSettingsParser = new CoverletSettingsParser(_eqtTrace);
+ CoverletSettings coverletSettings = coverletSettingsParser.Parse(_configurationElement, testModules);
+
+ // Build services container
+ _serviceProvider = _serviceCollectionFactory(_eqtTrace, _logger, coverletSettings.TestModule).BuildServiceProvider();
+
+ // Get coverage and attachment managers
+ _coverageManager = new CoverageManager(coverletSettings, _eqtTrace, _logger, _coverageWrapper,
+ _serviceProvider.GetRequiredService(), _serviceProvider.GetRequiredService(),
+ _serviceProvider.GetRequiredService(), _serviceProvider.GetRequiredService());
+
+ // Instrument modules
+ _coverageManager.InstrumentModules();
+ }
+ catch (Exception ex)
+ {
+ _logger.LogWarning(ex.ToString());
+ Dispose(true);
+ }
+ }
- // Remove vars
- _events = null;
- _dataSink = null;
- _coverageManager = null;
+ ///
+ /// SessionEnd event handler
+ ///
+ /// Sender
+ /// Event args
+ private void OnSessionEnd(object sender, SessionEndEventArgs e)
+ {
+ try
+ {
+ _eqtTrace.Verbose("{0}: SessionEnd received", CoverletConstants.DataCollectorName);
- base.Dispose(disposing);
- }
+ // Get coverage reports
+ IEnumerable<(string report, string fileName)> coverageReports = _coverageManager?.GetCoverageReports();
- ///
- /// SessionStart event handler
- ///
- /// Sender
- /// Event args
- private void OnSessionStart(object sender, SessionStartEventArgs sessionStartEventArgs)
+ if (coverageReports != null && coverageReports.Any())
{
- _eqtTrace.Verbose("{0}: SessionStart received", CoverletConstants.DataCollectorName);
-
- try
- {
- // Get coverlet settings
- IEnumerable testModules = GetTestModules(sessionStartEventArgs);
- var coverletSettingsParser = new CoverletSettingsParser(_eqtTrace);
- CoverletSettings coverletSettings = coverletSettingsParser.Parse(_configurationElement, testModules);
-
- // Build services container
- _serviceProvider = _serviceCollectionFactory(_eqtTrace, _logger, coverletSettings.TestModule).BuildServiceProvider();
-
- // Get coverage and attachment managers
- _coverageManager = new CoverageManager(coverletSettings, _eqtTrace, _logger, _coverageWrapper,
- _serviceProvider.GetRequiredService(), _serviceProvider.GetRequiredService(),
- _serviceProvider.GetRequiredService(), _serviceProvider.GetRequiredService());
-
- // Instrument modules
- _coverageManager.InstrumentModules();
- }
- catch (Exception ex)
- {
- _logger.LogWarning(ex.ToString());
- Dispose(true);
- }
+ // Send result attachments to test platform.
+ using var attachmentManager = new AttachmentManager(_dataSink, _dataCollectionContext, _logger, _eqtTrace, _countDownEventFactory.Create(coverageReports.Count(), TimeSpan.FromSeconds(30)));
+ foreach ((string report, string fileName) in coverageReports)
+ {
+ attachmentManager.SendCoverageReport(report, fileName);
+ }
}
-
- ///
- /// SessionEnd event handler
- ///
- /// Sender
- /// Event args
- private void OnSessionEnd(object sender, SessionEndEventArgs e)
+ else
{
- try
- {
- _eqtTrace.Verbose("{0}: SessionEnd received", CoverletConstants.DataCollectorName);
-
- // Get coverage reports
- IEnumerable<(string report, string fileName)> coverageReports = _coverageManager?.GetCoverageReports();
-
- if (coverageReports != null && coverageReports.Any())
- {
- // Send result attachments to test platform.
- using var attachmentManager = new AttachmentManager(_dataSink, _dataCollectionContext, _logger, _eqtTrace, _countDownEventFactory.Create(coverageReports.Count(), TimeSpan.FromSeconds(30)));
- foreach ((string report, string fileName) in coverageReports)
- {
- attachmentManager.SendCoverageReport(report, fileName);
- }
- }
- else
- {
- _eqtTrace.Verbose("{0}: No coverage reports specified", CoverletConstants.DataCollectorName);
- }
- }
- catch (Exception ex)
- {
- _logger.LogWarning(ex.ToString());
- Dispose(true);
- }
+ _eqtTrace.Verbose("{0}: No coverage reports specified", CoverletConstants.DataCollectorName);
}
+ }
+ catch (Exception ex)
+ {
+ _logger.LogWarning(ex.ToString());
+ Dispose(true);
+ }
+ }
- ///
- /// Gets test modules
- ///
- /// Event args
- /// Test modules list
- private IEnumerable GetTestModules(SessionStartEventArgs sessionStartEventArgs)
+ ///
+ /// Gets test modules
+ ///
+ /// Event args
+ /// Test modules list
+ private IEnumerable GetTestModules(SessionStartEventArgs sessionStartEventArgs)
+ {
+ try
+ {
+ IEnumerable testModules = GetPropertyValueWrapper(sessionStartEventArgs);
+ if (_eqtTrace.IsInfoEnabled)
{
- try
- {
- IEnumerable testModules = GetPropertyValueWrapper(sessionStartEventArgs);
- if (_eqtTrace.IsInfoEnabled)
- {
- _eqtTrace.Info("{0}: TestModules: '{1}'",
- CoverletConstants.DataCollectorName,
- string.Join(",", testModules ?? Enumerable.Empty()));
- }
- return testModules;
- }
- catch (MissingMethodException ex)
- {
- throw new MissingMethodException("Make sure to use .NET core SDK Version >= 2.2.300", ex);
- }
+ _eqtTrace.Info("{0}: TestModules: '{1}'",
+ CoverletConstants.DataCollectorName,
+ string.Join(",", testModules ?? Enumerable.Empty()));
}
+ return testModules;
+ }
+ catch (MissingMethodException ex)
+ {
+ throw new MissingMethodException("Make sure to use .NET core SDK Version >= 2.2.300", ex);
+ }
+ }
- ///
- /// Wraps GetPropertyValue to catch possible MissingMethodException on unsupported runtime
- ///
- ///
- ///
- private static IEnumerable GetPropertyValueWrapper(SessionStartEventArgs sessionStartEventArgs)
- {
- return sessionStartEventArgs.GetPropertyValue>(CoverletConstants.TestSourcesPropertyName);
- }
+ ///
+ /// Wraps GetPropertyValue to catch possible MissingMethodException on unsupported runtime
+ ///
+ ///
+ ///
+ private static IEnumerable GetPropertyValueWrapper(SessionStartEventArgs sessionStartEventArgs)
+ {
+ return sessionStartEventArgs.GetPropertyValue>(CoverletConstants.TestSourcesPropertyName);
+ }
- private static IServiceCollection GetDefaultServiceCollection(TestPlatformEqtTrace eqtTrace, TestPlatformLogger logger, string testModule)
- {
- IServiceCollection serviceCollection = new ServiceCollection();
- serviceCollection.AddTransient();
- serviceCollection.AddTransient();
- serviceCollection.AddTransient();
- serviceCollection.AddTransient();
- serviceCollection.AddTransient(_ => new CoverletLogger(eqtTrace, logger));
- // We need to keep singleton/static semantics
- serviceCollection.AddSingleton();
- // We cache resolutions
- serviceCollection.AddSingleton(serviceProvider =>
- new SourceRootTranslator(testModule, serviceProvider.GetRequiredService(), serviceProvider.GetRequiredService(), serviceProvider.GetRequiredService()));
- serviceCollection.AddSingleton();
- return serviceCollection;
- }
+ private static IServiceCollection GetDefaultServiceCollection(TestPlatformEqtTrace eqtTrace, TestPlatformLogger logger, string testModule)
+ {
+ IServiceCollection serviceCollection = new ServiceCollection();
+ serviceCollection.AddTransient();
+ serviceCollection.AddTransient();
+ serviceCollection.AddTransient();
+ serviceCollection.AddTransient();
+ serviceCollection.AddTransient(_ => new CoverletLogger(eqtTrace, logger));
+ // We need to keep singleton/static semantics
+ serviceCollection.AddSingleton();
+ // We cache resolutions
+ serviceCollection.AddSingleton(serviceProvider =>
+ new SourceRootTranslator(testModule, serviceProvider.GetRequiredService(), serviceProvider.GetRequiredService(), serviceProvider.GetRequiredService()));
+ serviceCollection.AddSingleton();
+ return serviceCollection;
}
+ }
}
diff --git a/src/coverlet.collector/DataCollection/CoverletLogger.cs b/src/coverlet.collector/DataCollection/CoverletLogger.cs
index 42eb6a1b2..543f5417d 100644
--- a/src/coverlet.collector/DataCollection/CoverletLogger.cs
+++ b/src/coverlet.collector/DataCollection/CoverletLogger.cs
@@ -7,64 +7,64 @@
namespace Coverlet.Collector.DataCollection
{
+ ///
+ /// Coverlet logger
+ ///
+ internal class CoverletLogger : ILogger
+ {
+ private readonly TestPlatformEqtTrace _eqtTrace;
+ private readonly TestPlatformLogger _logger;
+
+ public CoverletLogger(TestPlatformEqtTrace eqtTrace, TestPlatformLogger logger)
+ {
+ _eqtTrace = eqtTrace;
+ _logger = logger;
+ }
+
///
- /// Coverlet logger
+ /// Logs error
///
- internal class CoverletLogger : ILogger
+ /// Error message
+ public void LogError(string message)
{
- private readonly TestPlatformEqtTrace _eqtTrace;
- private readonly TestPlatformLogger _logger;
-
- public CoverletLogger(TestPlatformEqtTrace eqtTrace, TestPlatformLogger logger)
- {
- _eqtTrace = eqtTrace;
- _logger = logger;
- }
-
- ///
- /// Logs error
- ///
- /// Error message
- public void LogError(string message)
- {
- _logger.LogWarning(message);
- }
+ _logger.LogWarning(message);
+ }
- ///
- /// Logs error
- ///
- /// Exception to log
- public void LogError(Exception exception)
- {
- _logger.LogWarning(exception.ToString());
- }
+ ///
+ /// Logs error
+ ///
+ /// Exception to log
+ public void LogError(Exception exception)
+ {
+ _logger.LogWarning(exception.ToString());
+ }
- ///
- /// Logs information
- ///
- /// Information message
- /// importance
- public void LogInformation(string message, bool important = false)
- {
- _eqtTrace.Info(message);
- }
+ ///
+ /// Logs information
+ ///
+ /// Information message
+ /// importance
+ public void LogInformation(string message, bool important = false)
+ {
+ _eqtTrace.Info(message);
+ }
- ///
- /// Logs verbose
- ///
- /// Verbose message
- public void LogVerbose(string message)
- {
- _eqtTrace.Verbose(message);
- }
+ ///
+ /// Logs verbose
+ ///
+ /// Verbose message
+ public void LogVerbose(string message)
+ {
+ _eqtTrace.Verbose(message);
+ }
- ///
- /// Logs warning
- ///
- /// Warning message
- public void LogWarning(string message)
- {
- _eqtTrace.Warning(message);
- }
+ ///
+ /// Logs warning
+ ///
+ /// Warning message
+ public void LogWarning(string message)
+ {
+ _eqtTrace.Warning(message);
}
+ }
}
diff --git a/src/coverlet.collector/DataCollection/CoverletSettings.cs b/src/coverlet.collector/DataCollection/CoverletSettings.cs
index 2ebde799f..0c80687f9 100644
--- a/src/coverlet.collector/DataCollection/CoverletSettings.cs
+++ b/src/coverlet.collector/DataCollection/CoverletSettings.cs
@@ -6,106 +6,106 @@
namespace Coverlet.Collector.DataCollection
{
+ ///
+ /// Coverlet settings
+ ///
+ internal class CoverletSettings
+ {
///
- /// Coverlet settings
+ /// Test module
///
- internal class CoverletSettings
+ public string TestModule { get; set; }
+
+ ///
+ /// Report formats
+ ///
+ public string[] ReportFormats { get; set; }
+
+ ///
+ /// Filters to include
+ ///
+ public string[] IncludeFilters { get; set; }
+
+ ///
+ /// Directories to include
+ ///
+ public string[] IncludeDirectories { get; set; }
+
+ ///
+ /// Filters to exclude
+ ///
+ public string[] ExcludeFilters { get; set; }
+
+ ///
+ /// Source files to exclude
+ ///
+ public string[] ExcludeSourceFiles { get; set; }
+
+ ///
+ /// Attributes to exclude
+ ///
+ public string[] ExcludeAttributes { get; set; }
+
+ ///
+ /// Coverate report path to merge with
+ ///
+ public string MergeWith { get; set; }
+
+ ///
+ /// Use source link flag
+ ///
+ public bool UseSourceLink { get; set; }
+
+ ///
+ /// Single hit flag
+ ///
+ public bool SingleHit { get; set; }
+
+ ///
+ /// Includes test assembly
+ ///
+ public bool IncludeTestAssembly { get; set; }
+
+ ///
+ /// Neither track nor record auto-implemented properties.
+ ///
+ public bool SkipAutoProps { get; set; }
+
+ ///
+ /// Attributes that mark methods that never return.
+ ///
+ public string[] DoesNotReturnAttributes { get; set; }
+
+ ///
+ /// DeterministicReport flag
+ ///
+ public bool DeterministicReport { get; set; }
+
+ ///
+ /// Switch for heuristic to automatically exclude assemblies without source.
+ ///
+ public string ExcludeAssembliesWithoutSources { get; set; }
+
+ public override string ToString()
{
- ///
- /// Test module
- ///
- public string TestModule { get; set; }
-
- ///
- /// Report formats
- ///
- public string[] ReportFormats { get; set; }
-
- ///
- /// Filters to include
- ///
- public string[] IncludeFilters { get; set; }
-
- ///
- /// Directories to include
- ///
- public string[] IncludeDirectories { get; set; }
-
- ///
- /// Filters to exclude
- ///
- public string[] ExcludeFilters { get; set; }
-
- ///
- /// Source files to exclude
- ///
- public string[] ExcludeSourceFiles { get; set; }
-
- ///
- /// Attributes to exclude
- ///
- public string[] ExcludeAttributes { get; set; }
-
- ///
- /// Coverate report path to merge with
- ///
- public string MergeWith { get; set; }
-
- ///
- /// Use source link flag
- ///
- public bool UseSourceLink { get; set; }
-
- ///
- /// Single hit flag
- ///
- public bool SingleHit { get; set; }
-
- ///
- /// Includes test assembly
- ///
- public bool IncludeTestAssembly { get; set; }
-
- ///
- /// Neither track nor record auto-implemented properties.
- ///
- public bool SkipAutoProps { get; set; }
-
- ///
- /// Attributes that mark methods that never return.
- ///
- public string[] DoesNotReturnAttributes { get; set; }
-
- ///
- /// DeterministicReport flag
- ///
- public bool DeterministicReport { get; set; }
-
- ///
- /// Switch for heuristic to automatically exclude assemblies without source.
- ///
- public string ExcludeAssembliesWithoutSources { get; set; }
-
- public override string ToString()
- {
- var builder = new StringBuilder();
-
- builder.AppendFormat("TestModule: '{0}', ", TestModule);
- builder.AppendFormat("IncludeFilters: '{0}', ", string.Join(",", IncludeFilters ?? Enumerable.Empty()));
- builder.AppendFormat("IncludeDirectories: '{0}', ", string.Join(",", IncludeDirectories ?? Enumerable.Empty()));
- builder.AppendFormat("ExcludeFilters: '{0}', ", string.Join(",", ExcludeFilters ?? Enumerable.Empty()));
- builder.AppendFormat("ExcludeSourceFiles: '{0}', ", string.Join(",", ExcludeSourceFiles ?? Enumerable.Empty()));
- builder.AppendFormat("ExcludeAttributes: '{0}', ", string.Join(",", ExcludeAttributes ?? Enumerable.Empty()));
- builder.AppendFormat("MergeWith: '{0}', ", MergeWith);
- builder.AppendFormat("UseSourceLink: '{0}'", UseSourceLink);
- builder.AppendFormat("SingleHit: '{0}'", SingleHit);
- builder.AppendFormat("IncludeTestAssembly: '{0}'", IncludeTestAssembly);
- builder.AppendFormat("SkipAutoProps: '{0}'", SkipAutoProps);
- builder.AppendFormat("DoesNotReturnAttributes: '{0}'", string.Join(",", DoesNotReturnAttributes ?? Enumerable.Empty()));
- builder.AppendFormat("DeterministicReport: '{0}'", DeterministicReport);
- builder.AppendFormat("ExcludeAssembliesWithoutSources: '{0}'", ExcludeAssembliesWithoutSources);
-
- return builder.ToString();
- }
+ var builder = new StringBuilder();
+
+ builder.AppendFormat("TestModule: '{0}', ", TestModule);
+ builder.AppendFormat("IncludeFilters: '{0}', ", string.Join(",", IncludeFilters ?? Enumerable.Empty()));
+ builder.AppendFormat("IncludeDirectories: '{0}', ", string.Join(",", IncludeDirectories ?? Enumerable.Empty()));
+ builder.AppendFormat("ExcludeFilters: '{0}', ", string.Join(",", ExcludeFilters ?? Enumerable.Empty()));
+ builder.AppendFormat("ExcludeSourceFiles: '{0}', ", string.Join(",", ExcludeSourceFiles ?? Enumerable.Empty()));
+ builder.AppendFormat("ExcludeAttributes: '{0}', ", string.Join(",", ExcludeAttributes ?? Enumerable.Empty()));
+ builder.AppendFormat("MergeWith: '{0}', ", MergeWith);
+ builder.AppendFormat("UseSourceLink: '{0}'", UseSourceLink);
+ builder.AppendFormat("SingleHit: '{0}'", SingleHit);
+ builder.AppendFormat("IncludeTestAssembly: '{0}'", IncludeTestAssembly);
+ builder.AppendFormat("SkipAutoProps: '{0}'", SkipAutoProps);
+ builder.AppendFormat("DoesNotReturnAttributes: '{0}'", string.Join(",", DoesNotReturnAttributes ?? Enumerable.Empty()));
+ builder.AppendFormat("DeterministicReport: '{0}'", DeterministicReport);
+ builder.AppendFormat("ExcludeAssembliesWithoutSources: '{0}'", ExcludeAssembliesWithoutSources);
+
+ return builder.ToString();
}
+ }
}
diff --git a/src/coverlet.collector/DataCollection/CoverletSettingsParser.cs b/src/coverlet.collector/DataCollection/CoverletSettingsParser.cs
index 3776c98d4..29584281e 100644
--- a/src/coverlet.collector/DataCollection/CoverletSettingsParser.cs
+++ b/src/coverlet.collector/DataCollection/CoverletSettingsParser.cs
@@ -10,262 +10,262 @@
namespace Coverlet.Collector.DataCollection
{
+ ///
+ /// Coverlet settings parser
+ ///
+ internal class CoverletSettingsParser
+ {
+ private readonly TestPlatformEqtTrace _eqtTrace;
+
+ public CoverletSettingsParser(TestPlatformEqtTrace eqtTrace)
+ {
+ _eqtTrace = eqtTrace;
+ }
+
///
- /// Coverlet settings parser
+ /// Parser coverlet settings
///
- internal class CoverletSettingsParser
+ /// Configuration element
+ /// Test modules
+ /// Coverlet settings
+ public CoverletSettings Parse(XmlElement configurationElement, IEnumerable testModules)
{
- private readonly TestPlatformEqtTrace _eqtTrace;
+ var coverletSettings = new CoverletSettings
+ {
+ TestModule = ParseTestModule(testModules)
+ };
- public CoverletSettingsParser(TestPlatformEqtTrace eqtTrace)
- {
- _eqtTrace = eqtTrace;
- }
+ if (configurationElement != null)
+ {
+ coverletSettings.IncludeFilters = ParseIncludeFilters(configurationElement);
+ coverletSettings.IncludeDirectories = ParseIncludeDirectories(configurationElement);
+ coverletSettings.ExcludeAttributes = ParseExcludeAttributes(configurationElement);
+ coverletSettings.ExcludeSourceFiles = ParseExcludeSourceFiles(configurationElement);
+ coverletSettings.MergeWith = ParseMergeWith(configurationElement);
+ coverletSettings.UseSourceLink = ParseUseSourceLink(configurationElement);
+ coverletSettings.SingleHit = ParseSingleHit(configurationElement);
+ coverletSettings.IncludeTestAssembly = ParseIncludeTestAssembly(configurationElement);
+ coverletSettings.SkipAutoProps = ParseSkipAutoProps(configurationElement);
+ coverletSettings.DoesNotReturnAttributes = ParseDoesNotReturnAttributes(configurationElement);
+ coverletSettings.DeterministicReport = ParseDeterministicReport(configurationElement);
+ coverletSettings.ExcludeAssembliesWithoutSources = ParseExcludeAssembliesWithoutSources(configurationElement);
+ }
- ///
- /// Parser coverlet settings
- ///
- /// Configuration element
- /// Test modules
- /// Coverlet settings
- public CoverletSettings Parse(XmlElement configurationElement, IEnumerable testModules)
- {
- var coverletSettings = new CoverletSettings
- {
- TestModule = ParseTestModule(testModules)
- };
+ coverletSettings.ReportFormats = ParseReportFormats(configurationElement);
+ coverletSettings.ExcludeFilters = ParseExcludeFilters(configurationElement);
- if (configurationElement != null)
- {
- coverletSettings.IncludeFilters = ParseIncludeFilters(configurationElement);
- coverletSettings.IncludeDirectories = ParseIncludeDirectories(configurationElement);
- coverletSettings.ExcludeAttributes = ParseExcludeAttributes(configurationElement);
- coverletSettings.ExcludeSourceFiles = ParseExcludeSourceFiles(configurationElement);
- coverletSettings.MergeWith = ParseMergeWith(configurationElement);
- coverletSettings.UseSourceLink = ParseUseSourceLink(configurationElement);
- coverletSettings.SingleHit = ParseSingleHit(configurationElement);
- coverletSettings.IncludeTestAssembly = ParseIncludeTestAssembly(configurationElement);
- coverletSettings.SkipAutoProps = ParseSkipAutoProps(configurationElement);
- coverletSettings.DoesNotReturnAttributes = ParseDoesNotReturnAttributes(configurationElement);
- coverletSettings.DeterministicReport = ParseDeterministicReport(configurationElement);
- coverletSettings.ExcludeAssembliesWithoutSources = ParseExcludeAssembliesWithoutSources(configurationElement);
- }
+ if (_eqtTrace.IsVerboseEnabled)
+ {
+ _eqtTrace.Verbose("{0}: Initializing coverlet process with settings: \"{1}\"", CoverletConstants.DataCollectorName, coverletSettings.ToString());
+ }
- coverletSettings.ReportFormats = ParseReportFormats(configurationElement);
- coverletSettings.ExcludeFilters = ParseExcludeFilters(configurationElement);
+ return coverletSettings;
+ }
- if (_eqtTrace.IsVerboseEnabled)
- {
- _eqtTrace.Verbose("{0}: Initializing coverlet process with settings: \"{1}\"", CoverletConstants.DataCollectorName, coverletSettings.ToString());
- }
+ ///
+ /// Parses test module
+ ///
+ /// Test modules
+ /// Test module
+ private static string ParseTestModule(IEnumerable testModules)
+ {
+ // Validate if at least one source present.
+ if (testModules == null || !testModules.Any())
+ {
+ string errorMessage = string.Format(Resources.NoTestModulesFound, CoverletConstants.DataCollectorName);
+ throw new CoverletDataCollectorException(errorMessage);
+ }
- return coverletSettings;
- }
+ // Note:
+ // 1) .NET core test run supports one testModule per run. Coverlet also supports one testModule per run. So, we are using first testSource only and ignoring others.
+ // 2) If and when .NET full is supported with coverlet OR .NET core starts supporting multiple testModules, revisit this code to use other testModules as well.
+ return testModules.FirstOrDefault();
+ }
- ///
- /// Parses test module
- ///
- /// Test modules
- /// Test module
- private static string ParseTestModule(IEnumerable testModules)
- {
- // Validate if at least one source present.
- if (testModules == null || !testModules.Any())
- {
- string errorMessage = string.Format(Resources.NoTestModulesFound, CoverletConstants.DataCollectorName);
- throw new CoverletDataCollectorException(errorMessage);
- }
+ ///
+ /// Parse report formats
+ ///
+ /// Configuration element
+ /// Report formats
+ private static string[] ParseReportFormats(XmlElement configurationElement)
+ {
+ string[] formats = Array.Empty();
+ if (configurationElement != null)
+ {
+ XmlElement reportFormatElement = configurationElement[CoverletConstants.ReportFormatElementName];
+ formats = SplitElement(reportFormatElement);
+ }
- // Note:
- // 1) .NET core test run supports one testModule per run. Coverlet also supports one testModule per run. So, we are using first testSource only and ignoring others.
- // 2) If and when .NET full is supported with coverlet OR .NET core starts supporting multiple testModules, revisit this code to use other testModules as well.
- return testModules.FirstOrDefault();
- }
+ return formats is null || formats.Length == 0 ? new[] { CoverletConstants.DefaultReportFormat } : formats;
+ }
- ///
- /// Parse report formats
- ///
- /// Configuration element
- /// Report formats
- private static string[] ParseReportFormats(XmlElement configurationElement)
- {
- string[] formats = Array.Empty();
- if (configurationElement != null)
- {
- XmlElement reportFormatElement = configurationElement[CoverletConstants.ReportFormatElementName];
- formats = SplitElement(reportFormatElement);
- }
+ ///
+ /// Parse filters to include
+ ///
+ /// Configuration element
+ /// Filters to include
+ private static string[] ParseIncludeFilters(XmlElement configurationElement)
+ {
+ XmlElement includeFiltersElement = configurationElement[CoverletConstants.IncludeFiltersElementName];
+ return SplitElement(includeFiltersElement);
+ }
- return formats is null || formats.Length == 0 ? new[] { CoverletConstants.DefaultReportFormat } : formats;
- }
+ ///
+ /// Parse directories to include
+ ///
+ /// Configuration element
+ /// Directories to include
+ private static string[] ParseIncludeDirectories(XmlElement configurationElement)
+ {
+ XmlElement includeDirectoriesElement = configurationElement[CoverletConstants.IncludeDirectoriesElementName];
+ return SplitElement(includeDirectoriesElement);
+ }
- ///
- /// Parse filters to include
- ///
- /// Configuration element
- /// Filters to include
- private static string[] ParseIncludeFilters(XmlElement configurationElement)
- {
- XmlElement includeFiltersElement = configurationElement[CoverletConstants.IncludeFiltersElementName];
- return SplitElement(includeFiltersElement);
- }
+ ///
+ /// Parse filters to exclude
+ ///
+ /// Configuration element
+ /// Filters to exclude
+ private static string[] ParseExcludeFilters(XmlElement configurationElement)
+ {
+ var excludeFilters = new List { CoverletConstants.DefaultExcludeFilter };
- ///
- /// Parse directories to include
- ///
- /// Configuration element
- /// Directories to include
- private static string[] ParseIncludeDirectories(XmlElement configurationElement)
+ if (configurationElement != null)
+ {
+ XmlElement excludeFiltersElement = configurationElement[CoverletConstants.ExcludeFiltersElementName];
+ string[] filters = SplitElement(excludeFiltersElement);
+ if (filters != null)
{
- XmlElement includeDirectoriesElement = configurationElement[CoverletConstants.IncludeDirectoriesElementName];
- return SplitElement(includeDirectoriesElement);
+ excludeFilters.AddRange(filters);
}
+ }
- ///
- /// Parse filters to exclude
- ///
- /// Configuration element
- /// Filters to exclude
- private static string[] ParseExcludeFilters(XmlElement configurationElement)
- {
- var excludeFilters = new List { CoverletConstants.DefaultExcludeFilter };
-
- if (configurationElement != null)
- {
- XmlElement excludeFiltersElement = configurationElement[CoverletConstants.ExcludeFiltersElementName];
- string[] filters = SplitElement(excludeFiltersElement);
- if (filters != null)
- {
- excludeFilters.AddRange(filters);
- }
- }
-
- return excludeFilters.ToArray();
- }
+ return excludeFilters.ToArray();
+ }
- ///
- /// Parse source files to exclude
- ///
- /// Configuration element
- /// Source files to exclude
- private static string[] ParseExcludeSourceFiles(XmlElement configurationElement)
- {
- XmlElement excludeSourceFilesElement = configurationElement[CoverletConstants.ExcludeSourceFilesElementName];
- return SplitElement(excludeSourceFilesElement);
- }
+ ///
+ /// Parse source files to exclude
+ ///
+ /// Configuration element
+ /// Source files to exclude
+ private static string[] ParseExcludeSourceFiles(XmlElement configurationElement)
+ {
+ XmlElement excludeSourceFilesElement = configurationElement[CoverletConstants.ExcludeSourceFilesElementName];
+ return SplitElement(excludeSourceFilesElement);
+ }
- ///
- /// Parse attributes to exclude
- ///
- /// Configuration element
- /// Attributes to exclude
- private static string[] ParseExcludeAttributes(XmlElement configurationElement)
- {
- XmlElement excludeAttributesElement = configurationElement[CoverletConstants.ExcludeAttributesElementName];
- return SplitElement(excludeAttributesElement);
- }
+ ///
+ /// Parse attributes to exclude
+ ///
+ /// Configuration element
+ /// Attributes to exclude
+ private static string[] ParseExcludeAttributes(XmlElement configurationElement)
+ {
+ XmlElement excludeAttributesElement = configurationElement[CoverletConstants.ExcludeAttributesElementName];
+ return SplitElement(excludeAttributesElement);
+ }
- ///
- /// Parse merge with attribute
- ///
- /// Configuration element
- /// Merge with attribute
- private static string ParseMergeWith(XmlElement configurationElement)
- {
- XmlElement mergeWithElement = configurationElement[CoverletConstants.MergeWithElementName];
- return mergeWithElement?.InnerText;
- }
+ ///
+ /// Parse merge with attribute
+ ///
+ /// Configuration element
+ /// Merge with attribute
+ private static string ParseMergeWith(XmlElement configurationElement)
+ {
+ XmlElement mergeWithElement = configurationElement[CoverletConstants.MergeWithElementName];
+ return mergeWithElement?.InnerText;
+ }
- ///
- /// Parse use source link flag
- ///
- /// Configuration element
- /// Use source link flag
- private static bool ParseUseSourceLink(XmlElement configurationElement)
- {
- XmlElement useSourceLinkElement = configurationElement[CoverletConstants.UseSourceLinkElementName];
- bool.TryParse(useSourceLinkElement?.InnerText, out bool useSourceLink);
- return useSourceLink;
- }
+ ///
+ /// Parse use source link flag
+ ///
+ /// Configuration element
+ /// Use source link flag
+ private static bool ParseUseSourceLink(XmlElement configurationElement)
+ {
+ XmlElement useSourceLinkElement = configurationElement[CoverletConstants.UseSourceLinkElementName];
+ bool.TryParse(useSourceLinkElement?.InnerText, out bool useSourceLink);
+ return useSourceLink;
+ }
- ///
- /// Parse single hit flag
- ///
- /// Configuration element
- /// Single hit flag
- private static bool ParseSingleHit(XmlElement configurationElement)
- {
- XmlElement singleHitElement = configurationElement[CoverletConstants.SingleHitElementName];
- bool.TryParse(singleHitElement?.InnerText, out bool singleHit);
- return singleHit;
- }
+ ///
+ /// Parse single hit flag
+ ///
+ /// Configuration element
+ /// Single hit flag
+ private static bool ParseSingleHit(XmlElement configurationElement)
+ {
+ XmlElement singleHitElement = configurationElement[CoverletConstants.SingleHitElementName];
+ bool.TryParse(singleHitElement?.InnerText, out bool singleHit);
+ return singleHit;
+ }
- ///
- /// Parse ParseDeterministicReport flag
- ///
- /// Configuration element
- /// ParseDeterministicReport flag
- private static bool ParseDeterministicReport(XmlElement configurationElement)
- {
- XmlElement deterministicReportElement = configurationElement[CoverletConstants.DeterministicReport];
- bool.TryParse(deterministicReportElement?.InnerText, out bool deterministicReport);
- return deterministicReport;
- }
+ ///
+ /// Parse ParseDeterministicReport flag
+ ///
+ /// Configuration element
+ /// ParseDeterministicReport flag
+ private static bool ParseDeterministicReport(XmlElement configurationElement)
+ {
+ XmlElement deterministicReportElement = configurationElement[CoverletConstants.DeterministicReport];
+ bool.TryParse(deterministicReportElement?.InnerText, out bool deterministicReport);
+ return deterministicReport;
+ }
- ///
- /// Parse ExcludeAssembliesWithoutSources flag
- ///
- /// Configuration element
- /// ExcludeAssembliesWithoutSources flag
- private static string ParseExcludeAssembliesWithoutSources(XmlElement configurationElement)
- {
- XmlElement instrumentModulesWithoutLocalSourcesElement = configurationElement[CoverletConstants.ExcludeAssembliesWithoutSources];
- return instrumentModulesWithoutLocalSourcesElement?.InnerText;
- }
+ ///
+ /// Parse ExcludeAssembliesWithoutSources flag
+ ///
+ /// Configuration element
+ /// ExcludeAssembliesWithoutSources flag
+ private static string ParseExcludeAssembliesWithoutSources(XmlElement configurationElement)
+ {
+ XmlElement instrumentModulesWithoutLocalSourcesElement = configurationElement[CoverletConstants.ExcludeAssembliesWithoutSources];
+ return instrumentModulesWithoutLocalSourcesElement?.InnerText;
+ }
- ///
- /// Parse include test assembly flag
- ///
- /// Configuration element
- /// Include Test Assembly Flag
- private static bool ParseIncludeTestAssembly(XmlElement configurationElement)
- {
- XmlElement includeTestAssemblyElement = configurationElement[CoverletConstants.IncludeTestAssemblyElementName];
- bool.TryParse(includeTestAssemblyElement?.InnerText, out bool includeTestAssembly);
- return includeTestAssembly;
- }
+ ///
+ /// Parse include test assembly flag
+ ///
+ /// Configuration element
+ /// Include Test Assembly Flag
+ private static bool ParseIncludeTestAssembly(XmlElement configurationElement)
+ {
+ XmlElement includeTestAssemblyElement = configurationElement[CoverletConstants.IncludeTestAssemblyElementName];
+ bool.TryParse(includeTestAssemblyElement?.InnerText, out bool includeTestAssembly);
+ return includeTestAssembly;
+ }
- ///
- /// Parse skipautoprops flag
- ///
- /// Configuration element
- /// Include Test Assembly Flag
- private static bool ParseSkipAutoProps(XmlElement configurationElement)
- {
- XmlElement skipAutoPropsElement = configurationElement[CoverletConstants.SkipAutoProps];
- bool.TryParse(skipAutoPropsElement?.InnerText, out bool skipAutoProps);
- return skipAutoProps;
- }
+ ///
+ /// Parse skipautoprops flag
+ ///
+ /// Configuration element
+ /// Include Test Assembly Flag
+ private static bool ParseSkipAutoProps(XmlElement configurationElement)
+ {
+ XmlElement skipAutoPropsElement = configurationElement[CoverletConstants.SkipAutoProps];
+ bool.TryParse(skipAutoPropsElement?.InnerText, out bool skipAutoProps);
+ return skipAutoProps;
+ }
- ///
- /// Parse attributes that mark methods that do not return.
- ///
- /// Configuration element
- /// DoesNotReturn attributes
- private static string[] ParseDoesNotReturnAttributes(XmlElement configurationElement)
- {
- XmlElement doesNotReturnAttributesElement = configurationElement[CoverletConstants.DoesNotReturnAttributesElementName];
- return SplitElement(doesNotReturnAttributesElement);
- }
+ ///
+ /// Parse attributes that mark methods that do not return.
+ ///
+ /// Configuration element
+ /// DoesNotReturn attributes
+ private static string[] ParseDoesNotReturnAttributes(XmlElement configurationElement)
+ {
+ XmlElement doesNotReturnAttributesElement = configurationElement[CoverletConstants.DoesNotReturnAttributesElementName];
+ return SplitElement(doesNotReturnAttributesElement);
+ }
- ///
- /// Splits a comma separated elements into an array
- ///
- /// The element to split
- /// An array of the values in the element
- private static string[] SplitElement(XmlElement element)
- {
- return element?.InnerText?.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Where(value => !string.IsNullOrWhiteSpace(value)).Select(value => value.Trim()).ToArray();
- }
+ ///
+ /// Splits a comma separated elements into an array
+ ///
+ /// The element to split
+ /// An array of the values in the element
+ private static string[] SplitElement(XmlElement element)
+ {
+ return element?.InnerText?.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Where(value => !string.IsNullOrWhiteSpace(value)).Select(value => value.Trim()).ToArray();
}
+ }
}
diff --git a/src/coverlet.collector/InProcDataCollection/CoverletInProcDataCollector.cs b/src/coverlet.collector/InProcDataCollection/CoverletInProcDataCollector.cs
index f682b2687..b61d75f55 100644
--- a/src/coverlet.collector/InProcDataCollection/CoverletInProcDataCollector.cs
+++ b/src/coverlet.collector/InProcDataCollection/CoverletInProcDataCollector.cs
@@ -14,117 +14,117 @@
namespace Coverlet.Collector.DataCollection
{
- public class CoverletInProcDataCollector : InProcDataCollection
+ public class CoverletInProcDataCollector : InProcDataCollection
+ {
+ private TestPlatformEqtTrace _eqtTrace;
+ private bool _enableExceptionLog;
+
+ private void AttachDebugger()
{
- private TestPlatformEqtTrace _eqtTrace;
- private bool _enableExceptionLog;
+ if (int.TryParse(Environment.GetEnvironmentVariable("COVERLET_DATACOLLECTOR_INPROC_DEBUG"), out int result) && result == 1)
+ {
+ Debugger.Launch();
+ Debugger.Break();
+ }
+ }
- private void AttachDebugger()
- {
- if (int.TryParse(Environment.GetEnvironmentVariable("COVERLET_DATACOLLECTOR_INPROC_DEBUG"), out int result) && result == 1)
- {
- Debugger.Launch();
- Debugger.Break();
- }
- }
+ private void EnableExceptionLog()
+ {
+ if (int.TryParse(Environment.GetEnvironmentVariable("COVERLET_DATACOLLECTOR_INPROC_EXCEPTIONLOG_ENABLED"), out int result) && result == 1)
+ {
+ _enableExceptionLog = true;
+ }
+ }
- private void EnableExceptionLog()
- {
- if (int.TryParse(Environment.GetEnvironmentVariable("COVERLET_DATACOLLECTOR_INPROC_EXCEPTIONLOG_ENABLED"), out int result) && result == 1)
- {
- _enableExceptionLog = true;
- }
- }
+ public void Initialize(IDataCollectionSink dataCollectionSink)
+ {
+ AttachDebugger();
+ EnableExceptionLog();
- public void Initialize(IDataCollectionSink dataCollectionSink)
- {
- AttachDebugger();
- EnableExceptionLog();
+ _eqtTrace = new TestPlatformEqtTrace();
+ _eqtTrace.Verbose("Initialize CoverletInProcDataCollector");
+ }
- _eqtTrace = new TestPlatformEqtTrace();
- _eqtTrace.Verbose("Initialize CoverletInProcDataCollector");
- }
+ public void TestCaseEnd(TestCaseEndArgs testCaseEndArgs)
+ {
+ }
- public void TestCaseEnd(TestCaseEndArgs testCaseEndArgs)
+ public void TestCaseStart(TestCaseStartArgs testCaseStartArgs)
+ {
+ }
+
+ public void TestSessionEnd(TestSessionEndArgs testSessionEndArgs)
+ {
+ foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
+ {
+ Type injectedInstrumentationClass = GetInstrumentationClass(assembly);
+ if (injectedInstrumentationClass is null)
{
+ continue;
}
- public void TestCaseStart(TestCaseStartArgs testCaseStartArgs)
+ try
{
+ _eqtTrace.Verbose($"Calling ModuleTrackerTemplate.UnloadModule for '{injectedInstrumentationClass.Assembly.FullName}'");
+ MethodInfo unloadModule = injectedInstrumentationClass.GetMethod(nameof(ModuleTrackerTemplate.UnloadModule), new[] { typeof(object), typeof(EventArgs) });
+ unloadModule.Invoke(null, new[] { (object)this, EventArgs.Empty });
+ injectedInstrumentationClass.GetField("FlushHitFile", BindingFlags.Static | BindingFlags.Public).SetValue(null, false);
+ _eqtTrace.Verbose($"Called ModuleTrackerTemplate.UnloadModule for '{injectedInstrumentationClass.Assembly.FullName}'");
}
-
- public void TestSessionEnd(TestSessionEndArgs testSessionEndArgs)
+ catch (Exception ex)
{
- foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
- {
- Type injectedInstrumentationClass = GetInstrumentationClass(assembly);
- if (injectedInstrumentationClass is null)
- {
- continue;
- }
-
- try
- {
- _eqtTrace.Verbose($"Calling ModuleTrackerTemplate.UnloadModule for '{injectedInstrumentationClass.Assembly.FullName}'");
- MethodInfo unloadModule = injectedInstrumentationClass.GetMethod(nameof(ModuleTrackerTemplate.UnloadModule), new[] { typeof(object), typeof(EventArgs) });
- unloadModule.Invoke(null, new[] { (object)this, EventArgs.Empty });
- injectedInstrumentationClass.GetField("FlushHitFile", BindingFlags.Static | BindingFlags.Public).SetValue(null, false);
- _eqtTrace.Verbose($"Called ModuleTrackerTemplate.UnloadModule for '{injectedInstrumentationClass.Assembly.FullName}'");
- }
- catch (Exception ex)
- {
- if (_enableExceptionLog)
- {
- _eqtTrace.Error("{0}: Failed to unload module with error: {1}", CoverletConstants.InProcDataCollectorName, ex);
- string errorMessage = string.Format(Resources.FailedToUnloadModule, CoverletConstants.InProcDataCollectorName);
- throw new CoverletDataCollectorException(errorMessage, ex);
- }
- }
- }
+ if (_enableExceptionLog)
+ {
+ _eqtTrace.Error("{0}: Failed to unload module with error: {1}", CoverletConstants.InProcDataCollectorName, ex);
+ string errorMessage = string.Format(Resources.FailedToUnloadModule, CoverletConstants.InProcDataCollectorName);
+ throw new CoverletDataCollectorException(errorMessage, ex);
+ }
}
+ }
+ }
- public void TestSessionStart(TestSessionStartArgs testSessionStartArgs)
+ public void TestSessionStart(TestSessionStartArgs testSessionStartArgs)
+ {
+ }
+
+ private Type GetInstrumentationClass(Assembly assembly)
+ {
+ try
+ {
+ foreach (Type type in assembly.GetTypes())
{
+ if (type.Namespace == "Coverlet.Core.Instrumentation.Tracker"
+ && type.Name.StartsWith(assembly.GetName().Name + "_"))
+ {
+ return type;
+ }
}
- private Type GetInstrumentationClass(Assembly assembly)
+ return null;
+ }
+ catch (Exception ex)
+ {
+ if (_enableExceptionLog)
{
- try
+ var exceptionString = new StringBuilder();
+ exceptionString.AppendFormat("{0}: Failed to get Instrumentation class for assembly '{1}' with error: {2}",
+ CoverletConstants.InProcDataCollectorName, assembly, ex);
+ exceptionString.AppendLine();
+
+ if (ex is ReflectionTypeLoadException rtle)
+ {
+ exceptionString.AppendLine("ReflectionTypeLoadException list:");
+ foreach (Exception loaderEx in rtle.LoaderExceptions)
{
- foreach (Type type in assembly.GetTypes())
- {
- if (type.Namespace == "Coverlet.Core.Instrumentation.Tracker"
- && type.Name.StartsWith(assembly.GetName().Name + "_"))
- {
- return type;
- }
- }
-
- return null;
- }
- catch (Exception ex)
- {
- if (_enableExceptionLog)
- {
- var exceptionString = new StringBuilder();
- exceptionString.AppendFormat("{0}: Failed to get Instrumentation class for assembly '{1}' with error: {2}",
- CoverletConstants.InProcDataCollectorName, assembly, ex);
- exceptionString.AppendLine();
-
- if (ex is ReflectionTypeLoadException rtle)
- {
- exceptionString.AppendLine("ReflectionTypeLoadException list:");
- foreach (Exception loaderEx in rtle.LoaderExceptions)
- {
- exceptionString.AppendLine(loaderEx.ToString());
- }
- }
-
- _eqtTrace.Warning(exceptionString.ToString());
- }
-
- return null;
+ exceptionString.AppendLine(loaderEx.ToString());
}
+ }
+
+ _eqtTrace.Warning(exceptionString.ToString());
}
+
+ return null;
+ }
}
+ }
}
diff --git a/src/coverlet.collector/Properties/AssemblyInfo.cs b/src/coverlet.collector/Properties/AssemblyInfo.cs
index 4d4a63712..9d5c4a633 100644
--- a/src/coverlet.collector/Properties/AssemblyInfo.cs
+++ b/src/coverlet.collector/Properties/AssemblyInfo.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Toni Solarin-Sodara
+// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.Reflection;
@@ -8,4 +8,4 @@
[assembly: InternalsVisibleTo("coverlet.core.tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100757cf9291d78a82e5bb58a827a3c46c2f959318327ad30d1b52e918321ffbd847fb21565b8576d2a3a24562a93e86c77a298b564a0f1b98f63d7a1441a3a8bcc206da3ed09d5dacc76e122a109a9d3ac608e21a054d667a2bae98510a1f0f653c0e6f58f42b4b3934f6012f5ec4a09b3dfd3e14d437ede1424bdb722aead64ad")]
[assembly: InternalsVisibleTo("coverlet.collector.tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100ed0ed6af9693182615b8dcadc83c918b8d36312f86cefc69539d67d4189cd1b89420e7c3871802ffef7f5ca7816c68ad856c77bf7c230cc07824d96aa5d1237eebd30e246b9a14e22695fb26b40c800f74ea96619092cbd3a5d430d6c003fc7a82e8ccd1e315b935105d9232fe9e99e8d7ff54bba6f191959338d4a3169df9b3")]
// Needed to mock internal type https://github.com/Moq/moq4/wiki/Quickstart#advanced-features
-[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]
\ No newline at end of file
+[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]
diff --git a/src/coverlet.collector/Utilities/CountDownEvent.cs b/src/coverlet.collector/Utilities/CountDownEvent.cs
index 265c54103..9a82a76b3 100644
--- a/src/coverlet.collector/Utilities/CountDownEvent.cs
+++ b/src/coverlet.collector/Utilities/CountDownEvent.cs
@@ -7,36 +7,36 @@
namespace Coverlet.Collector.Utilities
{
- internal class CollectorCountdownEventFactory : ICountDownEventFactory
+ internal class CollectorCountdownEventFactory : ICountDownEventFactory
+ {
+ public ICountDownEvent Create(int count, TimeSpan waitTimeout)
{
- public ICountDownEvent Create(int count, TimeSpan waitTimeout)
- {
- return new CollectorCountdownEvent(count, waitTimeout);
- }
+ return new CollectorCountdownEvent(count, waitTimeout);
}
+ }
- internal class CollectorCountdownEvent : ICountDownEvent
- {
- private readonly CountdownEvent _countDownEvent;
- private readonly TimeSpan _waitTimeout;
+ internal class CollectorCountdownEvent : ICountDownEvent
+ {
+ private readonly CountdownEvent _countDownEvent;
+ private readonly TimeSpan _waitTimeout;
- public CollectorCountdownEvent(int count, TimeSpan waitTimeout)
- {
- _countDownEvent = new CountdownEvent(count);
- _waitTimeout = waitTimeout;
- }
+ public CollectorCountdownEvent(int count, TimeSpan waitTimeout)
+ {
+ _countDownEvent = new CountdownEvent(count);
+ _waitTimeout = waitTimeout;
+ }
- public void Signal()
- {
- _countDownEvent.Signal();
- }
+ public void Signal()
+ {
+ _countDownEvent.Signal();
+ }
- public void Wait()
- {
- if (!_countDownEvent.Wait(_waitTimeout))
- {
- throw new TimeoutException($"CollectorCountdownEvent timeout after {_waitTimeout}");
- }
- }
+ public void Wait()
+ {
+ if (!_countDownEvent.Wait(_waitTimeout))
+ {
+ throw new TimeoutException($"CollectorCountdownEvent timeout after {_waitTimeout}");
+ }
}
+ }
}
diff --git a/src/coverlet.collector/Utilities/CoverletConstants.cs b/src/coverlet.collector/Utilities/CoverletConstants.cs
index 3a7bfa998..5ce4a79ef 100644
--- a/src/coverlet.collector/Utilities/CoverletConstants.cs
+++ b/src/coverlet.collector/Utilities/CoverletConstants.cs
@@ -3,29 +3,29 @@
namespace Coverlet.Collector.Utilities
{
- internal static class CoverletConstants
- {
- public const string FriendlyName = "XPlat code coverage";
- public const string DefaultUri = @"datacollector://Microsoft/CoverletCodeCoverage/1.0";
- public const string DataCollectorName = "CoverletCoverageDataCollector";
- public const string DefaultReportFormat = "cobertura";
- public const string DefaultFileName = "coverage";
- public const string IncludeFiltersElementName = "Include";
- public const string IncludeDirectoriesElementName = "IncludeDirectory";
- public const string ExcludeFiltersElementName = "Exclude";
- public const string ExcludeSourceFilesElementName = "ExcludeByFile";
- public const string ExcludeAttributesElementName = "ExcludeByAttribute";
- public const string MergeWithElementName = "MergeWith";
- public const string UseSourceLinkElementName = "UseSourceLink";
- public const string SingleHitElementName = "SingleHit";
- public const string IncludeTestAssemblyElementName = "IncludeTestAssembly";
- public const string TestSourcesPropertyName = "TestSources";
- public const string ReportFormatElementName = "Format";
- public const string DefaultExcludeFilter = "[coverlet.*]*";
- public const string InProcDataCollectorName = "CoverletInProcDataCollector";
- public const string SkipAutoProps = "SkipAutoProps";
- public const string DoesNotReturnAttributesElementName = "DoesNotReturnAttribute";
- public const string DeterministicReport = "DeterministicReport";
- public const string ExcludeAssembliesWithoutSources = "ExcludeAssembliesWithoutSources";
- }
+ internal static class CoverletConstants
+ {
+ public const string FriendlyName = "XPlat code coverage";
+ public const string DefaultUri = @"datacollector://Microsoft/CoverletCodeCoverage/1.0";
+ public const string DataCollectorName = "CoverletCoverageDataCollector";
+ public const string DefaultReportFormat = "cobertura";
+ public const string DefaultFileName = "coverage";
+ public const string IncludeFiltersElementName = "Include";
+ public const string IncludeDirectoriesElementName = "IncludeDirectory";
+ public const string ExcludeFiltersElementName = "Exclude";
+ public const string ExcludeSourceFilesElementName = "ExcludeByFile";
+ public const string ExcludeAttributesElementName = "ExcludeByAttribute";
+ public const string MergeWithElementName = "MergeWith";
+ public const string UseSourceLinkElementName = "UseSourceLink";
+ public const string SingleHitElementName = "SingleHit";
+ public const string IncludeTestAssemblyElementName = "IncludeTestAssembly";
+ public const string TestSourcesPropertyName = "TestSources";
+ public const string ReportFormatElementName = "Format";
+ public const string DefaultExcludeFilter = "[coverlet.*]*";
+ public const string InProcDataCollectorName = "CoverletInProcDataCollector";
+ public const string SkipAutoProps = "SkipAutoProps";
+ public const string DoesNotReturnAttributesElementName = "DoesNotReturnAttribute";
+ public const string DeterministicReport = "DeterministicReport";
+ public const string ExcludeAssembliesWithoutSources = "ExcludeAssembliesWithoutSources";
+ }
}
diff --git a/src/coverlet.collector/Utilities/CoverletDataCollectorException.cs b/src/coverlet.collector/Utilities/CoverletDataCollectorException.cs
index 189b363f8..2b015d24e 100644
--- a/src/coverlet.collector/Utilities/CoverletDataCollectorException.cs
+++ b/src/coverlet.collector/Utilities/CoverletDataCollectorException.cs
@@ -5,14 +5,14 @@
namespace Coverlet.Collector.Utilities
{
- internal class CoverletDataCollectorException : Exception
+ internal class CoverletDataCollectorException : Exception
+ {
+ public CoverletDataCollectorException(string message) : base(message)
{
- public CoverletDataCollectorException(string message) : base(message)
- {
- }
+ }
- public CoverletDataCollectorException(string message, Exception innerException) : base(message, innerException)
- {
- }
+ public CoverletDataCollectorException(string message, Exception innerException) : base(message, innerException)
+ {
}
+ }
}
diff --git a/src/coverlet.collector/Utilities/DirectoryHelper.cs b/src/coverlet.collector/Utilities/DirectoryHelper.cs
index c9800a21b..35ef0ccf5 100644
--- a/src/coverlet.collector/Utilities/DirectoryHelper.cs
+++ b/src/coverlet.collector/Utilities/DirectoryHelper.cs
@@ -6,25 +6,25 @@
namespace Coverlet.Collector.Utilities
{
+ ///
+ internal class DirectoryHelper : IDirectoryHelper
+ {
///
- internal class DirectoryHelper : IDirectoryHelper
+ public bool Exists(string path)
{
- ///
- public bool Exists(string path)
- {
- return Directory.Exists(path);
- }
+ return Directory.Exists(path);
+ }
- ///
- public void CreateDirectory(string path)
- {
- Directory.CreateDirectory(path);
- }
+ ///
+ public void CreateDirectory(string path)
+ {
+ Directory.CreateDirectory(path);
+ }
- ///
- public void Delete(string path, bool recursive)
- {
- Directory.Delete(path, recursive);
- }
+ ///
+ public void Delete(string path, bool recursive)
+ {
+ Directory.Delete(path, recursive);
}
+ }
}
diff --git a/src/coverlet.collector/Utilities/FileHelper.cs b/src/coverlet.collector/Utilities/FileHelper.cs
index f8a85b13e..7f6ecaaf4 100644
--- a/src/coverlet.collector/Utilities/FileHelper.cs
+++ b/src/coverlet.collector/Utilities/FileHelper.cs
@@ -6,19 +6,19 @@
namespace Coverlet.Collector.Utilities
{
+ ///
+ internal class FileHelper : IFileHelper
+ {
///
- internal class FileHelper : IFileHelper
+ public bool Exists(string path)
{
- ///
- public bool Exists(string path)
- {
- return File.Exists(path);
- }
+ return File.Exists(path);
+ }
- ///
- public void WriteAllText(string path, string contents)
- {
- File.WriteAllText(path, contents);
- }
+ ///
+ public void WriteAllText(string path, string contents)
+ {
+ File.WriteAllText(path, contents);
}
+ }
}
diff --git a/src/coverlet.collector/Utilities/Interfaces/ICountDown.cs b/src/coverlet.collector/Utilities/Interfaces/ICountDown.cs
index 69eddbce4..a9b7b3354 100644
--- a/src/coverlet.collector/Utilities/Interfaces/ICountDown.cs
+++ b/src/coverlet.collector/Utilities/Interfaces/ICountDown.cs
@@ -6,33 +6,33 @@
namespace Coverlet.Collector.Utilities.Interfaces
{
+ ///
+ /// Factory for ICountDownEvent
+ ///
+ internal interface ICountDownEventFactory
+ {
///
- /// Factory for ICountDownEvent
+ /// Create ICountDownEvent instance
///
- internal interface ICountDownEventFactory
- {
- ///
- /// Create ICountDownEvent instance
- ///
- /// count of CountDownEvent
- /// max wait
- ///
- ICountDownEvent Create(int count, TimeSpan waitTimeout);
- }
+ /// count of CountDownEvent
+ /// max wait
+ ///
+ ICountDownEvent Create(int count, TimeSpan waitTimeout);
+ }
+ ///
+ /// Wrapper interface for CountDownEvent
+ ///
+ internal interface ICountDownEvent
+ {
///
- /// Wrapper interface for CountDownEvent
+ /// Signal event
///
- internal interface ICountDownEvent
- {
- ///
- /// Signal event
- ///
- void Signal();
+ void Signal();
- ///
- /// Wait for event
- ///
- void Wait();
- }
+ ///
+ /// Wait for event
+ ///
+ void Wait();
+ }
}
diff --git a/src/coverlet.collector/Utilities/Interfaces/ICoverageWrapper.cs b/src/coverlet.collector/Utilities/Interfaces/ICoverageWrapper.cs
index 1a34612c0..48410be09 100644
--- a/src/coverlet.collector/Utilities/Interfaces/ICoverageWrapper.cs
+++ b/src/coverlet.collector/Utilities/Interfaces/ICoverageWrapper.cs
@@ -7,37 +7,37 @@
namespace Coverlet.Collector.Utilities.Interfaces
{
+ ///
+ /// Wrapper interface for Coverage class in coverlet.core
+ /// Since the class is not testable, this interface is used to abstract methods for mocking in unit tests.
+ ///
+ internal interface ICoverageWrapper
+ {
///
- /// Wrapper interface for Coverage class in coverlet.core
- /// Since the class is not testable, this interface is used to abstract methods for mocking in unit tests.
+ /// Creates a coverage object from given coverlet settings
///
- internal interface ICoverageWrapper
- {
- ///
- /// Creates a coverage object from given coverlet settings
- ///
- /// Coverlet settings
- /// Coverlet logger
- /// Coverlet instrumentationHelper
- /// Coverlet fileSystem
- /// Coverlet sourceRootTranslator
- ///
- /// Coverage object
- Coverage CreateCoverage(CoverletSettings settings, ILogger logger, IInstrumentationHelper instrumentationHelper, IFileSystem fileSystem, ISourceRootTranslator sourceRootTranslator, ICecilSymbolHelper cecilSymbolHelper);
+ /// Coverlet settings
+ /// Coverlet logger
+ /// Coverlet instrumentationHelper
+ /// Coverlet fileSystem
+ /// Coverlet sourceRootTranslator
+ ///
+ /// Coverage object
+ Coverage CreateCoverage(CoverletSettings settings, ILogger logger, IInstrumentationHelper instrumentationHelper, IFileSystem fileSystem, ISourceRootTranslator sourceRootTranslator, ICecilSymbolHelper cecilSymbolHelper);
- ///
- /// Gets the coverage result from provided coverage object
- ///
- /// Coverage
- /// The coverage result
- CoverageResult GetCoverageResult(Coverage coverage);
+ ///
+ /// Gets the coverage result from provided coverage object
+ ///
+ /// Coverage
+ /// The coverage result
+ CoverageResult GetCoverageResult(Coverage coverage);
- ///
- /// Prepares modules for getting coverage.
- /// Wrapper over coverage.PrepareModules
- ///
- ///
- void PrepareModules(Coverage coverage);
+ ///
+ /// Prepares modules for getting coverage.
+ /// Wrapper over coverage.PrepareModules
+ ///
+ ///
+ void PrepareModules(Coverage coverage);
- }
+ }
}
diff --git a/src/coverlet.collector/Utilities/Interfaces/IDirectoryHelper.cs b/src/coverlet.collector/Utilities/Interfaces/IDirectoryHelper.cs
index f148f21ea..07ee98c21 100644
--- a/src/coverlet.collector/Utilities/Interfaces/IDirectoryHelper.cs
+++ b/src/coverlet.collector/Utilities/Interfaces/IDirectoryHelper.cs
@@ -3,29 +3,29 @@
namespace Coverlet.Collector.Utilities.Interfaces
{
- interface IDirectoryHelper
- {
- ///
- /// Determines whether the specified directory exists.
- ///
- /// The directory to check.
- /// true if the caller has the required permissions and path contains the name of an existing directory; otherwise, false.
- /// This method also returns false if path is null, an invalid path, or a zero-length string.
- /// If the caller does not have sufficient permissions to read the specified file,
- /// no exception is thrown and the method returns false regardless of the existence of path.
- bool Exists(string path);
+ interface IDirectoryHelper
+ {
+ ///
+ /// Determines whether the specified directory exists.
+ ///
+ /// The directory to check.
+ /// true if the caller has the required permissions and path contains the name of an existing directory; otherwise, false.
+ /// This method also returns false if path is null, an invalid path, or a zero-length string.
+ /// If the caller does not have sufficient permissions to read the specified file,
+ /// no exception is thrown and the method returns false regardless of the existence of path.
+ bool Exists(string path);
- ///
- /// Creates all directories and subdirectories in the specified path unless they already exist.
- ///
- /// The directory to create.
- void CreateDirectory(string directory);
+ ///
+ /// Creates all directories and subdirectories in the specified path unless they already exist.
+ ///
+ /// The directory to create.
+ void CreateDirectory(string directory);
- ///
- /// Deletes the specified directory and, if indicated, any subdirectories and files in the directory.
- ///
- /// The name of the directory to remove.
- /// true to remove directories, subdirectories, and files in path; otherwise, false.
- void Delete(string path, bool recursive);
- }
+ ///
+ /// Deletes the specified directory and, if indicated, any subdirectories and files in the directory.
+ ///
+ /// The name of the directory to remove.
+ /// true to remove directories, subdirectories, and files in path; otherwise, false.
+ void Delete(string path, bool recursive);
+ }
}
diff --git a/src/coverlet.collector/Utilities/Interfaces/IFileHelper.cs b/src/coverlet.collector/Utilities/Interfaces/IFileHelper.cs
index 1ddcc8678..c9c58bc21 100644
--- a/src/coverlet.collector/Utilities/Interfaces/IFileHelper.cs
+++ b/src/coverlet.collector/Utilities/Interfaces/IFileHelper.cs
@@ -3,24 +3,24 @@
namespace Coverlet.Collector.Utilities.Interfaces
{
- internal interface IFileHelper
- {
- ///
- /// Determines whether the specified file exists.
- ///
- /// The file to check.
- /// true if the caller has the required permissions and path contains the name of an existing file; otherwise, false.
- /// This method also returns false if path is null, an invalid path, or a zero-length string.
- /// If the caller does not have sufficient permissions to read the specified file,
- /// no exception is thrown and the method returns false regardless of the existence of path.
- bool Exists(string path);
+ internal interface IFileHelper
+ {
+ ///
+ /// Determines whether the specified file exists.
+ ///
+ /// The file to check.
+ /// true if the caller has the required permissions and path contains the name of an existing file; otherwise, false.
+ /// This method also returns false if path is null, an invalid path, or a zero-length string.
+ /// If the caller does not have sufficient permissions to read the specified file,
+ /// no exception is thrown and the method returns false regardless of the existence of path.
+ bool Exists(string path);
- ///
- /// Creates a new file, writes the specified string to the file, and then closes the file.
- /// If the target file already exists, it is overwritten.
- ///
- /// The file to write to.
- /// The string to write to the file.
- void WriteAllText(string path, string contents);
- }
+ ///
+ /// Creates a new file, writes the specified string to the file, and then closes the file.
+ /// If the target file already exists, it is overwritten.
+ ///
+ /// The file to write to.
+ /// The string to write to the file.
+ void WriteAllText(string path, string contents);
+ }
}
diff --git a/src/coverlet.collector/Utilities/TestPlatformEqtTrace.cs b/src/coverlet.collector/Utilities/TestPlatformEqtTrace.cs
index 7c02f6d03..a5cbdf16a 100644
--- a/src/coverlet.collector/Utilities/TestPlatformEqtTrace.cs
+++ b/src/coverlet.collector/Utilities/TestPlatformEqtTrace.cs
@@ -5,52 +5,52 @@
namespace Coverlet.Collector.Utilities
{
+ ///
+ /// Test platform eqttrace
+ ///
+ internal class TestPlatformEqtTrace
+ {
+ public bool IsInfoEnabled => EqtTrace.IsInfoEnabled;
+ public bool IsVerboseEnabled => EqtTrace.IsVerboseEnabled;
+
///
- /// Test platform eqttrace
+ /// Verbose logger
///
- internal class TestPlatformEqtTrace
+ /// Format
+ /// Args
+ public void Verbose(string format, params object[] args)
{
- public bool IsInfoEnabled => EqtTrace.IsInfoEnabled;
- public bool IsVerboseEnabled => EqtTrace.IsVerboseEnabled;
-
- ///
- /// Verbose logger
- ///
- /// Format
- /// Args
- public void Verbose(string format, params object[] args)
- {
- EqtTrace.Verbose($"[coverlet]{format}", args);
- }
+ EqtTrace.Verbose($"[coverlet]{format}", args);
+ }
- ///
- /// Warning logger
- ///
- /// Format
- /// Args
- public void Warning(string format, params object[] args)
- {
- EqtTrace.Warning($"[coverlet]{format}", args);
- }
+ ///
+ /// Warning logger
+ ///
+ /// Format
+ /// Args
+ public void Warning(string format, params object[] args)
+ {
+ EqtTrace.Warning($"[coverlet]{format}", args);
+ }
- ///
- /// Info logger
- ///
- /// Format
- /// Args
- public void Info(string format, params object[] args)
- {
- EqtTrace.Info($"[coverlet]{format}", args);
- }
+ ///
+ /// Info logger
+ ///
+ /// Format
+ /// Args
+ public void Info(string format, params object[] args)
+ {
+ EqtTrace.Info($"[coverlet]{format}", args);
+ }
- ///
- /// Error logger
- ///
- /// Format
- /// Args
- public void Error(string format, params object[] args)
- {
- EqtTrace.Error($"[coverlet]{format}", args);
- }
+ ///
+ /// Error logger
+ ///
+ /// Format
+ /// Args
+ public void Error(string format, params object[] args)
+ {
+ EqtTrace.Error($"[coverlet]{format}", args);
}
+ }
}
diff --git a/src/coverlet.collector/Utilities/TestPlatformLogger.cs b/src/coverlet.collector/Utilities/TestPlatformLogger.cs
index 105e4c9d9..dd3560220 100644
--- a/src/coverlet.collector/Utilities/TestPlatformLogger.cs
+++ b/src/coverlet.collector/Utilities/TestPlatformLogger.cs
@@ -5,27 +5,27 @@
namespace Coverlet.Collector.Utilities
{
+ ///
+ /// Test platform logger
+ ///
+ internal class TestPlatformLogger
+ {
+ private readonly DataCollectionLogger _logger;
+ private readonly DataCollectionContext _dataCollectionContext;
+
+ public TestPlatformLogger(DataCollectionLogger logger, DataCollectionContext dataCollectionContext)
+ {
+ _logger = logger;
+ _dataCollectionContext = dataCollectionContext;
+ }
+
///
- /// Test platform logger
+ /// Log warning
///
- internal class TestPlatformLogger
+ /// Warning message
+ public void LogWarning(string warning)
{
- private readonly DataCollectionLogger _logger;
- private readonly DataCollectionContext _dataCollectionContext;
-
- public TestPlatformLogger(DataCollectionLogger logger, DataCollectionContext dataCollectionContext)
- {
- _logger = logger;
- _dataCollectionContext = dataCollectionContext;
- }
-
- ///
- /// Log warning
- ///
- /// Warning message
- public void LogWarning(string warning)
- {
- _logger.LogWarning(_dataCollectionContext, $"[coverlet]{warning}");
- }
+ _logger.LogWarning(_dataCollectionContext, $"[coverlet]{warning}");
}
+ }
}
diff --git a/src/coverlet.console/ExitCodes.cs b/src/coverlet.console/ExitCodes.cs
index 670eda89a..93a7d395f 100644
--- a/src/coverlet.console/ExitCodes.cs
+++ b/src/coverlet.console/ExitCodes.cs
@@ -9,29 +9,29 @@
[Flags]
internal enum CommandExitCodes
{
- ///
- /// Indicates successful run of dotnet test without any test failure and coverage percentage above threshold if provided.
- ///
- Success = 0,
+ ///
+ /// Indicates successful run of dotnet test without any test failure and coverage percentage above threshold if provided.
+ ///
+ Success = 0,
- ///
- /// Indicates test failure by dotnet test.
- ///
- TestFailed = 1,
+ ///
+ /// Indicates test failure by dotnet test.
+ ///
+ TestFailed = 1,
- ///
- /// Indicates coverage percentage is below given threshold for one or more threshold type.
- ///
- CoverageBelowThreshold = 2,
+ ///
+ /// Indicates coverage percentage is below given threshold for one or more threshold type.
+ ///
+ CoverageBelowThreshold = 2,
- ///
- /// Indicates exception occurred during Coverlet process.
- ///
- Exception = 101,
+ ///
+ /// Indicates exception occurred during Coverlet process.
+ ///
+ Exception = 101,
- ///
- /// Indicates missing options or empty arguments for Coverlet process.
- ///
- CommandParsingException = 102
+ ///
+ /// Indicates missing options or empty arguments for Coverlet process.
+ ///
+ CommandParsingException = 102
}
diff --git a/src/coverlet.console/Logging/ConsoleLogger.cs b/src/coverlet.console/Logging/ConsoleLogger.cs
index 1e41af504..30aca3a20 100644
--- a/src/coverlet.console/Logging/ConsoleLogger.cs
+++ b/src/coverlet.console/Logging/ConsoleLogger.cs
@@ -7,40 +7,40 @@
namespace Coverlet.Console.Logging
{
- class ConsoleLogger : ILogger
- {
- private static readonly object s_sync = new();
-
- public LogLevel Level { get; set; } = LogLevel.Normal;
+ class ConsoleLogger : ILogger
+ {
+ private static readonly object s_sync = new();
+
+ public LogLevel Level { get; set; } = LogLevel.Normal;
+
+ public void LogError(string message) => Log(LogLevel.Quiet, message, ConsoleColor.Red);
- public void LogError(string message) => Log(LogLevel.Quiet, message, ConsoleColor.Red);
+ public void LogError(Exception exception) => LogError(exception.ToString());
- public void LogError(Exception exception) => LogError(exception.ToString());
+ public void LogInformation(string message, bool important = false) => Log(important ? LogLevel.Minimal : LogLevel.Normal, message, ForegroundColor);
- public void LogInformation(string message, bool important = false) => Log(important ? LogLevel.Minimal : LogLevel.Normal, message, ForegroundColor);
+ public void LogVerbose(string message) => Log(LogLevel.Detailed, message, ForegroundColor);
- public void LogVerbose(string message) => Log(LogLevel.Detailed, message, ForegroundColor);
+ public void LogWarning(string message) => Log(LogLevel.Quiet, message, ConsoleColor.Yellow);
- public void LogWarning(string message) => Log(LogLevel.Quiet, message, ConsoleColor.Yellow);
+ private void Log(LogLevel level, string message, ConsoleColor color)
+ {
+ if (level < Level) return;
- private void Log(LogLevel level, string message, ConsoleColor color)
+ lock (s_sync)
+ {
+ ConsoleColor currentForegroundColor;
+ if (color != (currentForegroundColor = ForegroundColor))
+ {
+ ForegroundColor = color;
+ WriteLine(message);
+ ForegroundColor = currentForegroundColor;
+ }
+ else
{
- if (level < Level) return;
-
- lock (s_sync)
- {
- ConsoleColor currentForegroundColor;
- if (color != (currentForegroundColor = ForegroundColor))
- {
- ForegroundColor = color;
- WriteLine(message);
- ForegroundColor = currentForegroundColor;
- }
- else
- {
- WriteLine(message);
- }
- }
+ WriteLine(message);
}
+ }
}
+ }
}
diff --git a/src/coverlet.console/Logging/LogLevel.cs b/src/coverlet.console/Logging/LogLevel.cs
index 2e0cf7320..4035d07bd 100644
--- a/src/coverlet.console/Logging/LogLevel.cs
+++ b/src/coverlet.console/Logging/LogLevel.cs
@@ -1,33 +1,33 @@
-// Copyright (c) Toni Solarin-Sodara
+// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Coverlet.Console.Logging
{
+ ///
+ /// Defines logging severity levels.
+ ///
+ enum LogLevel
+ {
///
- /// Defines logging severity levels.
+ /// Logs that track the general flow of the application. These logs should have long-term value.
///
- enum LogLevel
- {
- ///
- /// Logs that track the general flow of the application. These logs should have long-term value.
- ///
- Detailed = 0,
+ Detailed = 0,
- ///
- /// Logs that highlight an abnormal or unexpected event in the application flow, but do not otherwise cause the
- /// application execution to stop.
- ///
- Normal = 1,
+ ///
+ /// Logs that highlight an abnormal or unexpected event in the application flow, but do not otherwise cause the
+ /// application execution to stop.
+ ///
+ Normal = 1,
- ///
- /// Logs that highlight when the current flow of execution is stopped due to a failure. These should indicate a
- /// failure in the current activity, not an application-wide failure.
- ///
- Minimal = 2,
+ ///
+ /// Logs that highlight when the current flow of execution is stopped due to a failure. These should indicate a
+ /// failure in the current activity, not an application-wide failure.
+ ///
+ Minimal = 2,
- ///
- /// Not used for writing log messages. Specifies that a logging category should not write any messages except warning and errors.
- ///
- Quiet = 3
- }
+ ///
+ /// Not used for writing log messages. Specifies that a logging category should not write any messages except warning and errors.
+ ///
+ Quiet = 3
+ }
}
diff --git a/src/coverlet.console/Program.cs b/src/coverlet.console/Program.cs
index 73d848aaf..1a4bde021 100644
--- a/src/coverlet.console/Program.cs
+++ b/src/coverlet.console/Program.cs
@@ -3,14 +3,14 @@
using System;
using System.Collections.Generic;
+using System.CommandLine;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
-using System.Threading.Tasks;
using System.IO;
using System.Linq;
using System.Text;
-using System.CommandLine;
+using System.Threading.Tasks;
using ConsoleTables;
using Coverlet.Console.Logging;
using Coverlet.Core;
@@ -23,379 +23,379 @@
namespace Coverlet.Console
{
- public static class Program
+ public static class Program
+ {
+ static int Main(string[] args)
{
- static int Main(string[] args)
+ var moduleOrAppDirectory = new Argument("path", "Path to the test assembly or application directory.");
+ var target = new Option(new[] { "--target", "-t" }, "Path to the test runner application.") { Arity = ArgumentArity.ZeroOrOne, IsRequired = true };
+ var targs = new Option(new[] { "--targetargs", "-a" }, "Arguments to be passed to the test runner.") { Arity = ArgumentArity.ZeroOrOne };
+ var output = new Option(new[] { "--output", "-o" }, "Output of the generated coverage report") { Arity = ArgumentArity.ZeroOrOne };
+ var verbosity = new Option(new[] { "--verbosity", "-v" }, () => LogLevel.Normal, "Sets the verbosity level of the command. Allowed values are quiet, minimal, normal, detailed.") { Arity = ArgumentArity.ZeroOrOne };
+ var formats = new Option(new[] { "--format", "-f" }, () => new[] { "json" }, "Format of the generated coverage report.") { Arity = ArgumentArity.ZeroOrMore };
+ var threshold = new Option("--threshold", "Exits with error if the coverage % is below value.") { Arity = ArgumentArity.ZeroOrOne };
+ var thresholdTypes = new Option>("--threshold-type", () => new List(new string[] { "line", "branch", "method" }), "Coverage type to apply the threshold to.").FromAmong("line", "branch", "method");
+ var thresholdStat = new Option("--threshold-stat", () => ThresholdStatistic.Minimum, "Coverage statistic used to enforce the threshold value.") { Arity = ArgumentArity.ZeroOrMore };
+ var excludeFilters = new Option("--exclude", "Filter expressions to exclude specific modules and types.") { Arity = ArgumentArity.ZeroOrMore };
+ var includeFilters = new Option("--include", "Filter expressions to include only specific modules and types.") { Arity = ArgumentArity.ZeroOrMore };
+ var excludedSourceFiles = new Option("--exclude-by-file", "Glob patterns specifying source files to exclude.") { Arity = ArgumentArity.ZeroOrMore };
+ var includeDirectories = new Option("--include-directory", "Include directories containing additional assemblies to be instrumented.") { Arity = ArgumentArity.ZeroOrMore };
+ var excludeAttributes = new Option("--exclude-by-attribute", "Attributes to exclude from code coverage.") { Arity = ArgumentArity.ZeroOrOne };
+ var includeTestAssembly = new Option("--include-test-assembly", "Specifies whether to report code coverage of the test assembly.") { Arity = ArgumentArity.Zero };
+ var singleHit = new Option("--single-hit", "Specifies whether to limit code coverage hit reporting to a single hit for each location") { Arity = ArgumentArity.Zero };
+ var skipAutoProp = new Option("--skipautoprops", "Neither track nor record auto-implemented properties.") { Arity = ArgumentArity.Zero };
+ var mergeWith = new Option("--merge-with", "Path to existing coverage result to merge.") { Arity = ArgumentArity.ZeroOrOne };
+ var useSourceLink = new Option("--use-source-link", "Specifies whether to use SourceLink URIs in place of file system paths.") { Arity = ArgumentArity.Zero };
+ var doesNotReturnAttributes = new Option("--does-not-return-attribute", "Attributes that mark methods that do not return") { Arity = ArgumentArity.ZeroOrMore };
+ var excludeAssembliesWithoutSources = new Option("--exclude-assemblies-without-sources", "Specifies behaviour of heuristic to ignore assemblies with missing source documents.") { Arity = ArgumentArity.ZeroOrOne };
+
+ RootCommand rootCommand = new()
+ {
+ moduleOrAppDirectory,
+ target,
+ targs,
+ output,
+ verbosity,
+ formats,
+ threshold,
+ thresholdTypes,
+ thresholdStat,
+ excludeFilters,
+ includeFilters,
+ excludedSourceFiles,
+ includeDirectories,
+ excludeAttributes,
+ includeTestAssembly,
+ singleHit,
+ skipAutoProp,
+ mergeWith,
+ useSourceLink,
+ doesNotReturnAttributes,
+ excludeAssembliesWithoutSources
+ };
+
+ rootCommand.Description = "Cross platform .NET Core code coverage tool";
+
+ rootCommand.SetHandler(async (context) =>
+ {
+ string moduleOrAppDirectoryValue = context.ParseResult.GetValueForArgument(moduleOrAppDirectory);
+ string targetValue = context.ParseResult.GetValueForOption(target);
+ string targsValue = context.ParseResult.GetValueForOption(targs);
+ string outputValue = context.ParseResult.GetValueForOption(output);
+ LogLevel verbosityValue = context.ParseResult.GetValueForOption(verbosity);
+ string[] formatsValue = context.ParseResult.GetValueForOption(formats);
+ string thresholdValue = context.ParseResult.GetValueForOption(threshold);
+ List thresholdTypesValue = context.ParseResult.GetValueForOption(thresholdTypes);
+ ThresholdStatistic thresholdStatValue = context.ParseResult.GetValueForOption(thresholdStat);
+ string[] excludeFiltersValue = context.ParseResult.GetValueForOption(excludeFilters);
+ string[] includeFiltersValue = context.ParseResult.GetValueForOption(includeFilters);
+ string[] excludedSourceFilesValue = context.ParseResult.GetValueForOption(excludedSourceFiles);
+ string[] includeDirectoriesValue = context.ParseResult.GetValueForOption(includeDirectories);
+ string[] excludeAttributesValue = context.ParseResult.GetValueForOption(excludeAttributes);
+ bool includeTestAssemblyValue = context.ParseResult.GetValueForOption(includeTestAssembly);
+ bool singleHitValue = context.ParseResult.GetValueForOption(singleHit);
+ bool skipAutoPropValue = context.ParseResult.GetValueForOption(skipAutoProp);
+ string mergeWithValue = context.ParseResult.GetValueForOption(mergeWith);
+ bool useSourceLinkValue = context.ParseResult.GetValueForOption(useSourceLink);
+ string[] doesNotReturnAttributesValue = context.ParseResult.GetValueForOption(doesNotReturnAttributes);
+ string excludeAssembliesWithoutSourcesValue = context.ParseResult.GetValueForOption(excludeAssembliesWithoutSources);
+
+ if (string.IsNullOrEmpty(moduleOrAppDirectoryValue) || string.IsNullOrWhiteSpace(moduleOrAppDirectoryValue))
+ throw new ArgumentException("No test assembly or application directory specified.");
+
+ var taskStatus = await HandleCommand(moduleOrAppDirectoryValue,
+ targetValue,
+ targsValue,
+ outputValue,
+ verbosityValue,
+ formatsValue,
+ thresholdValue,
+ thresholdTypesValue,
+ thresholdStatValue,
+ excludeFiltersValue,
+ includeFiltersValue,
+ excludedSourceFilesValue,
+ includeDirectoriesValue,
+ excludeAttributesValue,
+ includeTestAssemblyValue,
+ singleHitValue,
+ skipAutoPropValue,
+ mergeWithValue,
+ useSourceLinkValue,
+ doesNotReturnAttributesValue,
+ excludeAssembliesWithoutSourcesValue);
+ context.ExitCode = taskStatus;
+
+ });
+ return rootCommand.Invoke(args);
+ }
+ private static Task HandleCommand(string moduleOrAppDirectory,
+ string target,
+ string targs,
+ string output,
+ LogLevel verbosity,
+ string[] formats,
+ string threshold,
+ List thresholdTypes,
+ ThresholdStatistic thresholdStat,
+ string[] excludeFilters,
+ string[] includeFilters,
+ string[] excludedSourceFiles,
+ string[] includeDirectories,
+ string[] excludeAttributes,
+ bool includeTestAssembly,
+ bool singleHit,
+ bool skipAutoProp,
+ string mergeWith,
+ bool useSourceLink,
+ string[] doesNotReturnAttributes,
+ string excludeAssembliesWithoutSources
+ )
+ {
+
+ IServiceCollection serviceCollection = new ServiceCollection();
+ serviceCollection.AddTransient();
+ serviceCollection.AddTransient();
+ serviceCollection.AddTransient();
+ serviceCollection.AddTransient();
+ // We need to keep singleton/static semantics
+ serviceCollection.AddSingleton();
+ serviceCollection.AddSingleton(provider => new SourceRootTranslator(provider.GetRequiredService(), provider.GetRequiredService()));
+ serviceCollection.AddSingleton();
+
+ ServiceProvider serviceProvider = serviceCollection.BuildServiceProvider();
+
+ var logger = (ConsoleLogger)serviceProvider.GetService();
+ IFileSystem fileSystem = serviceProvider.GetService();
+
+ // Adjust log level based on user input.
+ logger.Level = verbosity;
+ int exitCode = (int)CommandExitCodes.Success;
+
+ try
+ {
+ CoverageParameters parameters = new()
{
- var moduleOrAppDirectory = new Argument("path", "Path to the test assembly or application directory.");
- var target = new Option(new[] { "--target", "-t" }, "Path to the test runner application.") { Arity = ArgumentArity.ZeroOrOne, IsRequired = true };
- var targs = new Option(new[] { "--targetargs", "-a" }, "Arguments to be passed to the test runner.") { Arity = ArgumentArity.ZeroOrOne };
- var output = new Option(new[] { "--output", "-o" }, "Output of the generated coverage report") { Arity = ArgumentArity.ZeroOrOne };
- var verbosity = new Option(new[] { "--verbosity", "-v" }, () => LogLevel.Normal, "Sets the verbosity level of the command. Allowed values are quiet, minimal, normal, detailed.") { Arity = ArgumentArity.ZeroOrOne };
- var formats = new Option(new[] { "--format", "-f" }, () => new[] { "json" }, "Format of the generated coverage report.") { Arity = ArgumentArity.ZeroOrMore };
- var threshold = new Option("--threshold", "Exits with error if the coverage % is below value.") { Arity = ArgumentArity.ZeroOrOne };
- var thresholdTypes = new Option>("--threshold-type", () => new List(new string[] { "line", "branch", "method" }), "Coverage type to apply the threshold to.").FromAmong("line", "branch", "method");
- var thresholdStat = new Option("--threshold-stat", () => ThresholdStatistic.Minimum, "Coverage statistic used to enforce the threshold value.") { Arity = ArgumentArity.ZeroOrMore };
- var excludeFilters = new Option("--exclude", "Filter expressions to exclude specific modules and types.") { Arity = ArgumentArity.ZeroOrMore };
- var includeFilters = new Option("--include", "Filter expressions to include only specific modules and types.") { Arity = ArgumentArity.ZeroOrMore };
- var excludedSourceFiles = new Option("--exclude-by-file", "Glob patterns specifying source files to exclude.") { Arity = ArgumentArity.ZeroOrMore };
- var includeDirectories = new Option("--include-directory", "Include directories containing additional assemblies to be instrumented.") { Arity = ArgumentArity.ZeroOrMore };
- var excludeAttributes = new Option("--exclude-by-attribute", "Attributes to exclude from code coverage.") { Arity = ArgumentArity.ZeroOrOne };
- var includeTestAssembly = new Option("--include-test-assembly", "Specifies whether to report code coverage of the test assembly.") { Arity = ArgumentArity.Zero };
- var singleHit = new Option("--single-hit", "Specifies whether to limit code coverage hit reporting to a single hit for each location") { Arity = ArgumentArity.Zero };
- var skipAutoProp = new Option("--skipautoprops", "Neither track nor record auto-implemented properties.") { Arity = ArgumentArity.Zero };
- var mergeWith = new Option("--merge-with", "Path to existing coverage result to merge.") { Arity = ArgumentArity.ZeroOrOne };
- var useSourceLink = new Option("--use-source-link", "Specifies whether to use SourceLink URIs in place of file system paths.") { Arity = ArgumentArity.Zero };
- var doesNotReturnAttributes = new Option("--does-not-return-attribute", "Attributes that mark methods that do not return") { Arity = ArgumentArity.ZeroOrMore };
- var excludeAssembliesWithoutSources = new Option("--exclude-assemblies-without-sources", "Specifies behaviour of heuristic to ignore assemblies with missing source documents.") { Arity = ArgumentArity.ZeroOrOne };
-
- RootCommand rootCommand = new ()
- {
- moduleOrAppDirectory,
- target,
- targs,
- output,
- verbosity,
- formats,
- threshold,
- thresholdTypes,
- thresholdStat,
- excludeFilters,
- includeFilters,
- excludedSourceFiles,
- includeDirectories,
- excludeAttributes,
- includeTestAssembly,
- singleHit,
- skipAutoProp,
- mergeWith,
- useSourceLink,
- doesNotReturnAttributes,
- excludeAssembliesWithoutSources
- };
-
- rootCommand.Description = "Cross platform .NET Core code coverage tool";
-
- rootCommand.SetHandler(async (context) =>
- {
- string moduleOrAppDirectoryValue = context.ParseResult.GetValueForArgument(moduleOrAppDirectory);
- string targetValue = context.ParseResult.GetValueForOption(target);
- string targsValue = context.ParseResult.GetValueForOption(targs);
- string outputValue = context.ParseResult.GetValueForOption(output);
- LogLevel verbosityValue = context.ParseResult.GetValueForOption(verbosity);
- string[] formatsValue = context.ParseResult.GetValueForOption(formats);
- string thresholdValue = context.ParseResult.GetValueForOption(threshold);
- List thresholdTypesValue = context.ParseResult.GetValueForOption(thresholdTypes);
- ThresholdStatistic thresholdStatValue = context.ParseResult.GetValueForOption(thresholdStat);
- string[] excludeFiltersValue = context.ParseResult.GetValueForOption(excludeFilters);
- string[] includeFiltersValue = context.ParseResult.GetValueForOption(includeFilters);
- string[] excludedSourceFilesValue = context.ParseResult.GetValueForOption(excludedSourceFiles);
- string[] includeDirectoriesValue = context.ParseResult.GetValueForOption(includeDirectories);
- string[] excludeAttributesValue = context.ParseResult.GetValueForOption(excludeAttributes);
- bool includeTestAssemblyValue = context.ParseResult.GetValueForOption(includeTestAssembly);
- bool singleHitValue = context.ParseResult.GetValueForOption(singleHit);
- bool skipAutoPropValue = context.ParseResult.GetValueForOption(skipAutoProp);
- string mergeWithValue = context.ParseResult.GetValueForOption(mergeWith);
- bool useSourceLinkValue = context.ParseResult.GetValueForOption(useSourceLink);
- string[] doesNotReturnAttributesValue = context.ParseResult.GetValueForOption(doesNotReturnAttributes);
- string excludeAssembliesWithoutSourcesValue = context.ParseResult.GetValueForOption(excludeAssembliesWithoutSources);
-
- if (string.IsNullOrEmpty(moduleOrAppDirectoryValue) || string.IsNullOrWhiteSpace(moduleOrAppDirectoryValue))
- throw new ArgumentException("No test assembly or application directory specified.");
-
- var taskStatus = await HandleCommand(moduleOrAppDirectoryValue,
- targetValue,
- targsValue,
- outputValue,
- verbosityValue,
- formatsValue,
- thresholdValue,
- thresholdTypesValue,
- thresholdStatValue,
- excludeFiltersValue,
- includeFiltersValue,
- excludedSourceFilesValue,
- includeDirectoriesValue,
- excludeAttributesValue,
- includeTestAssemblyValue,
- singleHitValue,
- skipAutoPropValue,
- mergeWithValue,
- useSourceLinkValue,
- doesNotReturnAttributesValue,
- excludeAssembliesWithoutSourcesValue);
- context.ExitCode = taskStatus;
-
- });
- return rootCommand.Invoke(args);
- }
- private static Task HandleCommand(string moduleOrAppDirectory,
- string target,
- string targs,
- string output,
- LogLevel verbosity,
- string[] formats,
- string threshold,
- List thresholdTypes,
- ThresholdStatistic thresholdStat,
- string[] excludeFilters,
- string[] includeFilters,
- string[] excludedSourceFiles,
- string[] includeDirectories,
- string[] excludeAttributes,
- bool includeTestAssembly,
- bool singleHit,
- bool skipAutoProp,
- string mergeWith,
- bool useSourceLink,
- string[] doesNotReturnAttributes,
- string excludeAssembliesWithoutSources
- )
- {
+ IncludeFilters = includeFilters,
+ IncludeDirectories = includeDirectories,
+ ExcludeFilters = excludeFilters,
+ ExcludedSourceFiles = excludedSourceFiles,
+ ExcludeAttributes = excludeAttributes,
+ IncludeTestAssembly = includeTestAssembly,
+ SingleHit = singleHit,
+ MergeWith = mergeWith,
+ UseSourceLink = useSourceLink,
+ SkipAutoProps = skipAutoProp,
+ DoesNotReturnAttributes = doesNotReturnAttributes,
+ ExcludeAssembliesWithoutSources = excludeAssembliesWithoutSources
+ };
+ ISourceRootTranslator sourceRootTranslator = serviceProvider.GetRequiredService();
+
+ Coverage coverage = new(moduleOrAppDirectory,
+ parameters,
+ logger,
+ serviceProvider.GetRequiredService(),
+ fileSystem,
+ sourceRootTranslator,
+ serviceProvider.GetRequiredService());
+ coverage.PrepareModules();
+
+ Process process = new();
+ process.StartInfo.FileName = target;
+ process.StartInfo.Arguments = targs ?? string.Empty;
+ process.StartInfo.CreateNoWindow = true;
+ process.StartInfo.RedirectStandardOutput = true;
+ process.StartInfo.RedirectStandardError = true;
+ process.OutputDataReceived += (sender, eventArgs) =>
+ {
+ if (!string.IsNullOrEmpty(eventArgs.Data))
+ logger.LogInformation(eventArgs.Data, important: true);
+ };
- IServiceCollection serviceCollection = new ServiceCollection();
- serviceCollection.AddTransient();
- serviceCollection.AddTransient();
- serviceCollection.AddTransient();
- serviceCollection.AddTransient();
- // We need to keep singleton/static semantics
- serviceCollection.AddSingleton();
- serviceCollection.AddSingleton(provider => new SourceRootTranslator(provider.GetRequiredService(), provider.GetRequiredService()));
- serviceCollection.AddSingleton();
+ process.ErrorDataReceived += (sender, eventArgs) =>
+ {
+ if (!string.IsNullOrEmpty(eventArgs.Data))
+ logger.LogError(eventArgs.Data);
+ };
- ServiceProvider serviceProvider = serviceCollection.BuildServiceProvider();
+ process.Start();
- var logger = (ConsoleLogger)serviceProvider.GetService();
- IFileSystem fileSystem = serviceProvider.GetService();
+ process.BeginErrorReadLine();
+ process.BeginOutputReadLine();
- // Adjust log level based on user input.
- logger.Level = verbosity;
- int exitCode = (int)CommandExitCodes.Success;
+ process.WaitForExit();
- try
- {
- CoverageParameters parameters = new()
- {
- IncludeFilters = includeFilters,
- IncludeDirectories = includeDirectories,
- ExcludeFilters = excludeFilters,
- ExcludedSourceFiles = excludedSourceFiles,
- ExcludeAttributes = excludeAttributes,
- IncludeTestAssembly = includeTestAssembly,
- SingleHit = singleHit,
- MergeWith = mergeWith,
- UseSourceLink = useSourceLink,
- SkipAutoProps = skipAutoProp,
- DoesNotReturnAttributes = doesNotReturnAttributes,
- ExcludeAssembliesWithoutSources = excludeAssembliesWithoutSources
- };
- ISourceRootTranslator sourceRootTranslator = serviceProvider.GetRequiredService();
-
- Coverage coverage = new(moduleOrAppDirectory,
- parameters,
- logger,
- serviceProvider.GetRequiredService(),
- fileSystem,
- sourceRootTranslator,
- serviceProvider.GetRequiredService());
- coverage.PrepareModules();
-
- Process process = new();
- process.StartInfo.FileName = target;
- process.StartInfo.Arguments = targs ?? string.Empty;
- process.StartInfo.CreateNoWindow = true;
- process.StartInfo.RedirectStandardOutput = true;
- process.StartInfo.RedirectStandardError = true;
- process.OutputDataReceived += (sender, eventArgs) =>
- {
- if (!string.IsNullOrEmpty(eventArgs.Data))
- logger.LogInformation(eventArgs.Data, important: true);
- };
-
- process.ErrorDataReceived += (sender, eventArgs) =>
- {
- if (!string.IsNullOrEmpty(eventArgs.Data))
- logger.LogError(eventArgs.Data);
- };
-
- process.Start();
-
- process.BeginErrorReadLine();
- process.BeginOutputReadLine();
-
- process.WaitForExit();
-
- string dOutput = output != null ? output : Directory.GetCurrentDirectory() + Path.DirectorySeparatorChar.ToString();
-
- logger.LogInformation("\nCalculating coverage result...");
-
- CoverageResult result = coverage.GetCoverageResult();
-
- string directory = Path.GetDirectoryName(dOutput);
- if (directory == string.Empty)
- {
- directory = Directory.GetCurrentDirectory();
- }
- else if (!Directory.Exists(directory))
- {
- Directory.CreateDirectory(directory);
- }
-
- foreach (string format in formats)
- {
- IReporter reporter = new ReporterFactory(format).CreateReporter();
- if (reporter == null)
- {
- throw new Exception($"Specified output format '{format}' is not supported");
- }
-
- if (reporter.OutputType == ReporterOutputType.Console)
- {
- // Output to console
- logger.LogInformation(" Outputting results to console", important: true);
- logger.LogInformation(reporter.Report(result, sourceRootTranslator), important: true);
- }
- else
- {
- // Output to file
- string filename = Path.GetFileName(dOutput);
- filename = (filename == string.Empty) ? $"coverage.{reporter.Extension}" : filename;
- filename = Path.HasExtension(filename) ? filename : $"{filename}.{reporter.Extension}";
-
- string report = Path.Combine(directory, filename);
- logger.LogInformation($" Generating report '{report}'", important: true);
- fileSystem.WriteAllText(report, reporter.Report(result, sourceRootTranslator));
- }
- }
-
- var thresholdTypeFlagQueue = new Queue();
-
- foreach (string thresholdType in thresholdTypes)
- {
- if (thresholdType.Equals("line", StringComparison.OrdinalIgnoreCase))
- {
- thresholdTypeFlagQueue.Enqueue(ThresholdTypeFlags.Line);
- }
- else if (thresholdType.Equals("branch", StringComparison.OrdinalIgnoreCase))
- {
- thresholdTypeFlagQueue.Enqueue(ThresholdTypeFlags.Branch);
- }
- else if (thresholdType.Equals("method", StringComparison.OrdinalIgnoreCase))
- {
- thresholdTypeFlagQueue.Enqueue(ThresholdTypeFlags.Method);
- }
- }
-
- var thresholdTypeFlagValues = new Dictionary();
- if (!string.IsNullOrEmpty(threshold) && threshold.Contains(','))
- {
- IEnumerable thresholdValues = threshold.Split(',', StringSplitOptions.RemoveEmptyEntries).Select(t => t.Trim());
- if (thresholdValues.Count() != thresholdTypeFlagQueue.Count)
- {
- throw new Exception($"Threshold type flag count ({thresholdTypeFlagQueue.Count}) and values count ({thresholdValues.Count()}) doesn't match");
- }
-
- foreach (string thresholdValue in thresholdValues)
- {
- if (double.TryParse(thresholdValue, out double value))
- {
- thresholdTypeFlagValues[thresholdTypeFlagQueue.Dequeue()] = value;
- }
- else
- {
- throw new Exception($"Invalid threshold value must be numeric");
- }
- }
- }
- else
- {
- double thresholdValue = threshold != null ? double.Parse(threshold) : 0;
-
- while (thresholdTypeFlagQueue.Any())
- {
- thresholdTypeFlagValues[thresholdTypeFlagQueue.Dequeue()] = thresholdValue;
- }
- }
-
- var coverageTable = new ConsoleTable("Module", "Line", "Branch", "Method");
- var summary = new CoverageSummary();
-
- CoverageDetails linePercentCalculation = summary.CalculateLineCoverage(result.Modules);
- CoverageDetails branchPercentCalculation = summary.CalculateBranchCoverage(result.Modules);
- CoverageDetails methodPercentCalculation = summary.CalculateMethodCoverage(result.Modules);
-
- double totalLinePercent = linePercentCalculation.Percent;
- double totalBranchPercent = branchPercentCalculation.Percent;
- double totalMethodPercent = methodPercentCalculation.Percent;
-
- double averageLinePercent = linePercentCalculation.AverageModulePercent;
- double averageBranchPercent = branchPercentCalculation.AverageModulePercent;
- double averageMethodPercent = methodPercentCalculation.AverageModulePercent;
-
- foreach (KeyValuePair _module in result.Modules)
- {
- double linePercent = summary.CalculateLineCoverage(_module.Value).Percent;
- double branchPercent = summary.CalculateBranchCoverage(_module.Value).Percent;
- double methodPercent = summary.CalculateMethodCoverage(_module.Value).Percent;
-
- coverageTable.AddRow(Path.GetFileNameWithoutExtension(_module.Key), $"{InvariantFormat(linePercent)}%", $"{InvariantFormat(branchPercent)}%", $"{InvariantFormat(methodPercent)}%");
- }
-
- logger.LogInformation(coverageTable.ToStringAlternative());
-
- coverageTable.Columns.Clear();
- coverageTable.Rows.Clear();
-
- coverageTable.AddColumn(new[] { "", "Line", "Branch", "Method" });
- coverageTable.AddRow("Total", $"{InvariantFormat(totalLinePercent)}%", $"{InvariantFormat(totalBranchPercent)}%", $"{InvariantFormat(totalMethodPercent)}%");
- coverageTable.AddRow("Average", $"{InvariantFormat(averageLinePercent)}%", $"{InvariantFormat(averageBranchPercent)}%", $"{InvariantFormat(averageMethodPercent)}%");
-
- logger.LogInformation(coverageTable.ToStringAlternative());
- if (process.ExitCode > 0)
- {
- exitCode += (int)CommandExitCodes.TestFailed;
- }
-
- ThresholdTypeFlags thresholdTypeFlags = result.GetThresholdTypesBelowThreshold(summary, thresholdTypeFlagValues, thresholdStat);
- if (thresholdTypeFlags != ThresholdTypeFlags.None)
- {
- exitCode += (int)CommandExitCodes.CoverageBelowThreshold;
- var exceptionMessageBuilder = new StringBuilder();
- if ((thresholdTypeFlags & ThresholdTypeFlags.Line) != ThresholdTypeFlags.None)
- {
- exceptionMessageBuilder.AppendLine($"The {thresholdStat.ToString().ToLower()} line coverage is below the specified {thresholdTypeFlagValues[ThresholdTypeFlags.Line]}");
- }
-
- if ((thresholdTypeFlags & ThresholdTypeFlags.Branch) != ThresholdTypeFlags.None)
- {
- exceptionMessageBuilder.AppendLine($"The {thresholdStat.ToString().ToLower()} branch coverage is below the specified {thresholdTypeFlagValues[ThresholdTypeFlags.Branch]}");
- }
-
- if ((thresholdTypeFlags & ThresholdTypeFlags.Method) != ThresholdTypeFlags.None)
- {
- exceptionMessageBuilder.AppendLine($"The {thresholdStat.ToString().ToLower()} method coverage is below the specified {thresholdTypeFlagValues[ThresholdTypeFlags.Method]}");
- }
- throw new Exception(exceptionMessageBuilder.ToString());
- }
-
- return Task.FromResult(exitCode);
+ string dOutput = output != null ? output : Directory.GetCurrentDirectory() + Path.DirectorySeparatorChar.ToString();
+ logger.LogInformation("\nCalculating coverage result...");
- }
+ CoverageResult result = coverage.GetCoverageResult();
+
+ string directory = Path.GetDirectoryName(dOutput);
+ if (directory == string.Empty)
+ {
+ directory = Directory.GetCurrentDirectory();
+ }
+ else if (!Directory.Exists(directory))
+ {
+ Directory.CreateDirectory(directory);
+ }
+
+ foreach (string format in formats)
+ {
+ IReporter reporter = new ReporterFactory(format).CreateReporter();
+ if (reporter == null)
+ {
+ throw new Exception($"Specified output format '{format}' is not supported");
+ }
+
+ if (reporter.OutputType == ReporterOutputType.Console)
+ {
+ // Output to console
+ logger.LogInformation(" Outputting results to console", important: true);
+ logger.LogInformation(reporter.Report(result, sourceRootTranslator), important: true);
+ }
+ else
+ {
+ // Output to file
+ string filename = Path.GetFileName(dOutput);
+ filename = (filename == string.Empty) ? $"coverage.{reporter.Extension}" : filename;
+ filename = Path.HasExtension(filename) ? filename : $"{filename}.{reporter.Extension}";
+
+ string report = Path.Combine(directory, filename);
+ logger.LogInformation($" Generating report '{report}'", important: true);
+ fileSystem.WriteAllText(report, reporter.Report(result, sourceRootTranslator));
+ }
+ }
+
+ var thresholdTypeFlagQueue = new Queue();
- catch (Win32Exception we) when (we.Source == "System.Diagnostics.Process")
+ foreach (string thresholdType in thresholdTypes)
+ {
+ if (thresholdType.Equals("line", StringComparison.OrdinalIgnoreCase))
+ {
+ thresholdTypeFlagQueue.Enqueue(ThresholdTypeFlags.Line);
+ }
+ else if (thresholdType.Equals("branch", StringComparison.OrdinalIgnoreCase))
+ {
+ thresholdTypeFlagQueue.Enqueue(ThresholdTypeFlags.Branch);
+ }
+ else if (thresholdType.Equals("method", StringComparison.OrdinalIgnoreCase))
+ {
+ thresholdTypeFlagQueue.Enqueue(ThresholdTypeFlags.Method);
+ }
+ }
+
+ var thresholdTypeFlagValues = new Dictionary();
+ if (!string.IsNullOrEmpty(threshold) && threshold.Contains(','))
+ {
+ IEnumerable thresholdValues = threshold.Split(',', StringSplitOptions.RemoveEmptyEntries).Select(t => t.Trim());
+ if (thresholdValues.Count() != thresholdTypeFlagQueue.Count)
+ {
+ throw new Exception($"Threshold type flag count ({thresholdTypeFlagQueue.Count}) and values count ({thresholdValues.Count()}) doesn't match");
+ }
+
+ foreach (string thresholdValue in thresholdValues)
+ {
+ if (double.TryParse(thresholdValue, out double value))
{
- logger.LogError($"Start process '{target}' failed with '{we.Message}'");
- return Task.FromResult(exitCode > 0 ? exitCode : (int)CommandExitCodes.Exception);
+ thresholdTypeFlagValues[thresholdTypeFlagQueue.Dequeue()] = value;
}
- catch (Exception ex)
+ else
{
- logger.LogError(ex.Message);
- return Task.FromResult(exitCode > 0 ? exitCode : (int)CommandExitCodes.Exception);
+ throw new Exception($"Invalid threshold value must be numeric");
}
+ }
+ }
+ else
+ {
+ double thresholdValue = threshold != null ? double.Parse(threshold) : 0;
+
+ while (thresholdTypeFlagQueue.Any())
+ {
+ thresholdTypeFlagValues[thresholdTypeFlagQueue.Dequeue()] = thresholdValue;
+ }
+ }
+
+ var coverageTable = new ConsoleTable("Module", "Line", "Branch", "Method");
+ var summary = new CoverageSummary();
+
+ CoverageDetails linePercentCalculation = summary.CalculateLineCoverage(result.Modules);
+ CoverageDetails branchPercentCalculation = summary.CalculateBranchCoverage(result.Modules);
+ CoverageDetails methodPercentCalculation = summary.CalculateMethodCoverage(result.Modules);
+
+ double totalLinePercent = linePercentCalculation.Percent;
+ double totalBranchPercent = branchPercentCalculation.Percent;
+ double totalMethodPercent = methodPercentCalculation.Percent;
+
+ double averageLinePercent = linePercentCalculation.AverageModulePercent;
+ double averageBranchPercent = branchPercentCalculation.AverageModulePercent;
+ double averageMethodPercent = methodPercentCalculation.AverageModulePercent;
+
+ foreach (KeyValuePair _module in result.Modules)
+ {
+ double linePercent = summary.CalculateLineCoverage(_module.Value).Percent;
+ double branchPercent = summary.CalculateBranchCoverage(_module.Value).Percent;
+ double methodPercent = summary.CalculateMethodCoverage(_module.Value).Percent;
+ coverageTable.AddRow(Path.GetFileNameWithoutExtension(_module.Key), $"{InvariantFormat(linePercent)}%", $"{InvariantFormat(branchPercent)}%", $"{InvariantFormat(methodPercent)}%");
}
- static string InvariantFormat(double value) => value.ToString(CultureInfo.InvariantCulture);
+ logger.LogInformation(coverageTable.ToStringAlternative());
+
+ coverageTable.Columns.Clear();
+ coverageTable.Rows.Clear();
+
+ coverageTable.AddColumn(new[] { "", "Line", "Branch", "Method" });
+ coverageTable.AddRow("Total", $"{InvariantFormat(totalLinePercent)}%", $"{InvariantFormat(totalBranchPercent)}%", $"{InvariantFormat(totalMethodPercent)}%");
+ coverageTable.AddRow("Average", $"{InvariantFormat(averageLinePercent)}%", $"{InvariantFormat(averageBranchPercent)}%", $"{InvariantFormat(averageMethodPercent)}%");
+
+ logger.LogInformation(coverageTable.ToStringAlternative());
+ if (process.ExitCode > 0)
+ {
+ exitCode += (int)CommandExitCodes.TestFailed;
+ }
+
+ ThresholdTypeFlags thresholdTypeFlags = result.GetThresholdTypesBelowThreshold(summary, thresholdTypeFlagValues, thresholdStat);
+ if (thresholdTypeFlags != ThresholdTypeFlags.None)
+ {
+ exitCode += (int)CommandExitCodes.CoverageBelowThreshold;
+ var exceptionMessageBuilder = new StringBuilder();
+ if ((thresholdTypeFlags & ThresholdTypeFlags.Line) != ThresholdTypeFlags.None)
+ {
+ exceptionMessageBuilder.AppendLine($"The {thresholdStat.ToString().ToLower()} line coverage is below the specified {thresholdTypeFlagValues[ThresholdTypeFlags.Line]}");
+ }
+
+ if ((thresholdTypeFlags & ThresholdTypeFlags.Branch) != ThresholdTypeFlags.None)
+ {
+ exceptionMessageBuilder.AppendLine($"The {thresholdStat.ToString().ToLower()} branch coverage is below the specified {thresholdTypeFlagValues[ThresholdTypeFlags.Branch]}");
+ }
+
+ if ((thresholdTypeFlags & ThresholdTypeFlags.Method) != ThresholdTypeFlags.None)
+ {
+ exceptionMessageBuilder.AppendLine($"The {thresholdStat.ToString().ToLower()} method coverage is below the specified {thresholdTypeFlagValues[ThresholdTypeFlags.Method]}");
+ }
+ throw new Exception(exceptionMessageBuilder.ToString());
+ }
+
+ return Task.FromResult(exitCode);
+
+
+ }
+
+ catch (Win32Exception we) when (we.Source == "System.Diagnostics.Process")
+ {
+ logger.LogError($"Start process '{target}' failed with '{we.Message}'");
+ return Task.FromResult(exitCode > 0 ? exitCode : (int)CommandExitCodes.Exception);
+ }
+ catch (Exception ex)
+ {
+ logger.LogError(ex.Message);
+ return Task.FromResult(exitCode > 0 ? exitCode : (int)CommandExitCodes.Exception);
+ }
+
}
+
+ static string InvariantFormat(double value) => value.ToString(CultureInfo.InvariantCulture);
+ }
}
diff --git a/src/coverlet.console/Properties/AssemblyInfo.cs b/src/coverlet.console/Properties/AssemblyInfo.cs
index 59db2a82f..aff16fa56 100644
--- a/src/coverlet.console/Properties/AssemblyInfo.cs
+++ b/src/coverlet.console/Properties/AssemblyInfo.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Toni Solarin-Sodara
+// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-[assembly: System.Reflection.AssemblyKeyFileAttribute("coverlet.console.snk")]
\ No newline at end of file
+[assembly: System.Reflection.AssemblyKeyFileAttribute("coverlet.console.snk")]
diff --git a/src/coverlet.core/Abstractions/IAssemblyAdapter.cs b/src/coverlet.core/Abstractions/IAssemblyAdapter.cs
index 48b23084b..a020bced5 100644
--- a/src/coverlet.core/Abstractions/IAssemblyAdapter.cs
+++ b/src/coverlet.core/Abstractions/IAssemblyAdapter.cs
@@ -3,8 +3,8 @@
namespace Coverlet.Core.Abstractions
{
- internal interface IAssemblyAdapter
- {
- string GetAssemblyName(string assemblyPath);
- }
+ internal interface IAssemblyAdapter
+ {
+ string GetAssemblyName(string assemblyPath);
+ }
}
diff --git a/src/coverlet.core/Abstractions/ICecilSymbolHelper.cs b/src/coverlet.core/Abstractions/ICecilSymbolHelper.cs
index 06cdde3d1..b22463b5d 100644
--- a/src/coverlet.core/Abstractions/ICecilSymbolHelper.cs
+++ b/src/coverlet.core/Abstractions/ICecilSymbolHelper.cs
@@ -8,10 +8,10 @@
namespace Coverlet.Core.Abstractions
{
- internal interface ICecilSymbolHelper
- {
- IReadOnlyList GetBranchPoints(MethodDefinition methodDefinition);
- bool SkipNotCoverableInstruction(MethodDefinition methodDefinition, Instruction instruction);
- bool SkipInlineAssignedAutoProperty(bool skipAutoProps, MethodDefinition methodDefinition, Instruction instruction);
- }
+ internal interface ICecilSymbolHelper
+ {
+ IReadOnlyList GetBranchPoints(MethodDefinition methodDefinition);
+ bool SkipNotCoverableInstruction(MethodDefinition methodDefinition, Instruction instruction);
+ bool SkipInlineAssignedAutoProperty(bool skipAutoProps, MethodDefinition methodDefinition, Instruction instruction);
+ }
}
diff --git a/src/coverlet.core/Abstractions/IConsole.cs b/src/coverlet.core/Abstractions/IConsole.cs
index 72991cac5..2724ccf8b 100644
--- a/src/coverlet.core/Abstractions/IConsole.cs
+++ b/src/coverlet.core/Abstractions/IConsole.cs
@@ -3,8 +3,8 @@
namespace Coverlet.Core.Abstractions
{
- internal interface IConsole
- {
- public void WriteLine(string value);
- }
+ internal interface IConsole
+ {
+ public void WriteLine(string value);
+ }
}
diff --git a/src/coverlet.core/Abstractions/IFileSystem.cs b/src/coverlet.core/Abstractions/IFileSystem.cs
index cb710c758..6f0978467 100644
--- a/src/coverlet.core/Abstractions/IFileSystem.cs
+++ b/src/coverlet.core/Abstractions/IFileSystem.cs
@@ -5,24 +5,24 @@
namespace Coverlet.Core.Abstractions
{
- internal interface IFileSystem
- {
- bool Exists(string path);
+ internal interface IFileSystem
+ {
+ bool Exists(string path);
- void WriteAllText(string path, string contents);
+ void WriteAllText(string path, string contents);
- string ReadAllText(string path);
+ string ReadAllText(string path);
- Stream OpenRead(string path);
+ Stream OpenRead(string path);
- void Copy(string sourceFileName, string destFileName, bool overwrite);
+ void Copy(string sourceFileName, string destFileName, bool overwrite);
- void Delete(string path);
+ void Delete(string path);
- Stream NewFileStream(string path, FileMode mode);
+ Stream NewFileStream(string path, FileMode mode);
- Stream NewFileStream(string path, FileMode mode, FileAccess access);
+ Stream NewFileStream(string path, FileMode mode, FileAccess access);
- string[] ReadAllLines(string path);
- }
+ string[] ReadAllLines(string path);
+ }
}
diff --git a/src/coverlet.core/Abstractions/IInstrumentationHelper.cs b/src/coverlet.core/Abstractions/IInstrumentationHelper.cs
index 65af40011..fee916509 100644
--- a/src/coverlet.core/Abstractions/IInstrumentationHelper.cs
+++ b/src/coverlet.core/Abstractions/IInstrumentationHelper.cs
@@ -5,21 +5,21 @@
namespace Coverlet.Core.Abstractions
{
- internal interface IInstrumentationHelper
- {
- void BackupOriginalModule(string module, string identifier);
- void DeleteHitsFile(string path);
- string[] GetCoverableModules(string module, string[] directories, bool includeTestAssembly);
- bool HasPdb(string module, out bool embedded);
- bool IsModuleExcluded(string module, string[] excludeFilters);
- bool IsModuleIncluded(string module, string[] includeFilters);
- bool IsValidFilterExpression(string filter);
- bool IsTypeExcluded(string module, string type, string[] excludeFilters);
- bool IsTypeIncluded(string module, string type, string[] includeFilters);
- void RestoreOriginalModule(string module, string identifier);
- bool EmbeddedPortablePdbHasLocalSource(string module, AssemblySearchType excludeAssembliesWithoutSources);
- bool PortablePdbHasLocalSource(string module, AssemblySearchType excludeAssembliesWithoutSources);
- bool IsLocalMethod(string method);
- void SetLogger(ILogger logger);
- }
+ internal interface IInstrumentationHelper
+ {
+ void BackupOriginalModule(string module, string identifier);
+ void DeleteHitsFile(string path);
+ string[] GetCoverableModules(string module, string[] directories, bool includeTestAssembly);
+ bool HasPdb(string module, out bool embedded);
+ bool IsModuleExcluded(string module, string[] excludeFilters);
+ bool IsModuleIncluded(string module, string[] includeFilters);
+ bool IsValidFilterExpression(string filter);
+ bool IsTypeExcluded(string module, string type, string[] excludeFilters);
+ bool IsTypeIncluded(string module, string type, string[] includeFilters);
+ void RestoreOriginalModule(string module, string identifier);
+ bool EmbeddedPortablePdbHasLocalSource(string module, AssemblySearchType excludeAssembliesWithoutSources);
+ bool PortablePdbHasLocalSource(string module, AssemblySearchType excludeAssembliesWithoutSources);
+ bool IsLocalMethod(string method);
+ void SetLogger(ILogger logger);
+ }
}
diff --git a/src/coverlet.core/Abstractions/ILogger.cs b/src/coverlet.core/Abstractions/ILogger.cs
index c3e6ef15e..c03831531 100644
--- a/src/coverlet.core/Abstractions/ILogger.cs
+++ b/src/coverlet.core/Abstractions/ILogger.cs
@@ -1,16 +1,16 @@
-// Copyright (c) Toni Solarin-Sodara
+// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
namespace Coverlet.Core.Abstractions
{
- internal interface ILogger
- {
- void LogVerbose(string message);
- void LogInformation(string message, bool important = false);
- void LogWarning(string message);
- void LogError(string message);
- void LogError(Exception exception);
- }
-}
\ No newline at end of file
+ internal interface ILogger
+ {
+ void LogVerbose(string message);
+ void LogInformation(string message, bool important = false);
+ void LogWarning(string message);
+ void LogError(string message);
+ void LogError(Exception exception);
+ }
+}
diff --git a/src/coverlet.core/Abstractions/IProcessExitHandler.cs b/src/coverlet.core/Abstractions/IProcessExitHandler.cs
index 635015946..c0f9d524c 100644
--- a/src/coverlet.core/Abstractions/IProcessExitHandler.cs
+++ b/src/coverlet.core/Abstractions/IProcessExitHandler.cs
@@ -5,8 +5,8 @@
namespace Coverlet.Core.Abstractions
{
- internal interface IProcessExitHandler
- {
- void Add(EventHandler handler);
- }
+ internal interface IProcessExitHandler
+ {
+ void Add(EventHandler handler);
+ }
}
diff --git a/src/coverlet.core/Abstractions/IReporter.cs b/src/coverlet.core/Abstractions/IReporter.cs
index 9e497d62a..82441aa37 100644
--- a/src/coverlet.core/Abstractions/IReporter.cs
+++ b/src/coverlet.core/Abstractions/IReporter.cs
@@ -1,19 +1,19 @@
-// Copyright (c) Toni Solarin-Sodara
+// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Coverlet.Core.Abstractions
{
- internal interface IReporter
- {
- ReporterOutputType OutputType { get; }
- string Format { get; }
- string Extension { get; }
- string Report(CoverageResult result, ISourceRootTranslator sourceRootTranslator);
- }
+ internal interface IReporter
+ {
+ ReporterOutputType OutputType { get; }
+ string Format { get; }
+ string Extension { get; }
+ string Report(CoverageResult result, ISourceRootTranslator sourceRootTranslator);
+ }
- internal enum ReporterOutputType
- {
- File,
- Console,
- }
-}
\ No newline at end of file
+ internal enum ReporterOutputType
+ {
+ File,
+ Console,
+ }
+}
diff --git a/src/coverlet.core/Abstractions/IRetryHelper.cs b/src/coverlet.core/Abstractions/IRetryHelper.cs
index 88a1b29d5..85f8b53bb 100644
--- a/src/coverlet.core/Abstractions/IRetryHelper.cs
+++ b/src/coverlet.core/Abstractions/IRetryHelper.cs
@@ -5,9 +5,9 @@
namespace Coverlet.Core.Abstractions
{
- internal interface IRetryHelper
- {
- void Retry(Action action, Func backoffStrategy, int maxAttemptCount = 3);
- T Do(Func action, Func backoffStrategy, int maxAttemptCount = 3);
- }
+ internal interface IRetryHelper
+ {
+ void Retry(Action action, Func backoffStrategy, int maxAttemptCount = 3);
+ T Do(Func action, Func backoffStrategy, int maxAttemptCount = 3);
+ }
}
diff --git a/src/coverlet.core/Abstractions/ISourceRootTranslator.cs b/src/coverlet.core/Abstractions/ISourceRootTranslator.cs
index 4af6cfddf..2bbef7a87 100644
--- a/src/coverlet.core/Abstractions/ISourceRootTranslator.cs
+++ b/src/coverlet.core/Abstractions/ISourceRootTranslator.cs
@@ -6,11 +6,11 @@
namespace Coverlet.Core.Abstractions
{
- internal interface ISourceRootTranslator
- {
- bool AddMappingInCache(string originalFileName, string targetFileName);
- string ResolveFilePath(string originalFileName);
- string ResolveDeterministicPath(string originalFileName);
- IReadOnlyList ResolvePathRoot(string pathRoot);
- }
+ internal interface ISourceRootTranslator
+ {
+ bool AddMappingInCache(string originalFileName, string targetFileName);
+ string ResolveFilePath(string originalFileName);
+ string ResolveDeterministicPath(string originalFileName);
+ IReadOnlyList ResolvePathRoot(string pathRoot);
+ }
}
diff --git a/src/coverlet.core/Attributes/DoesNotReturnAttribute.cs b/src/coverlet.core/Attributes/DoesNotReturnAttribute.cs
index cebe198f1..074d0a59f 100644
--- a/src/coverlet.core/Attributes/DoesNotReturnAttribute.cs
+++ b/src/coverlet.core/Attributes/DoesNotReturnAttribute.cs
@@ -5,6 +5,6 @@
namespace Coverlet.Core.Attributes
{
- [AttributeUsage(AttributeTargets.Property | AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Class)]
- internal class DoesNotReturnAttribute : Attribute { }
+ [AttributeUsage(AttributeTargets.Property | AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Class)]
+ internal class DoesNotReturnAttribute : Attribute { }
}
diff --git a/src/coverlet.core/Attributes/ExcludeFromCoverage.cs b/src/coverlet.core/Attributes/ExcludeFromCoverage.cs
index 71efcb7bc..1436c2175 100644
--- a/src/coverlet.core/Attributes/ExcludeFromCoverage.cs
+++ b/src/coverlet.core/Attributes/ExcludeFromCoverage.cs
@@ -1,10 +1,10 @@
-// Copyright (c) Toni Solarin-Sodara
+// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
namespace Coverlet.Core.Attributes
{
- [AttributeUsage(AttributeTargets.Property | AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Class)]
- internal sealed class ExcludeFromCoverageAttribute : Attribute { }
-}
\ No newline at end of file
+ [AttributeUsage(AttributeTargets.Property | AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Class)]
+ internal sealed class ExcludeFromCoverageAttribute : Attribute { }
+}
diff --git a/src/coverlet.core/CoverageDetails.cs b/src/coverlet.core/CoverageDetails.cs
index 59db863c2..0359fa11a 100644
--- a/src/coverlet.core/CoverageDetails.cs
+++ b/src/coverlet.core/CoverageDetails.cs
@@ -1,30 +1,30 @@
-// Copyright (c) Toni Solarin-Sodara
+// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
namespace Coverlet.Core
{
- internal class CoverageDetails
- {
- private double _averageModulePercent;
+ internal class CoverageDetails
+ {
+ private double _averageModulePercent;
- public Modules Modules { get; internal set; }
- public double Covered { get; internal set; }
- public int Total { get; internal set; }
- public double Percent
- {
- get
- {
- if (Modules?.Count == 0) return 0;
- return Total == 0 ? 100D : Math.Floor((Covered / Total) * 10000) / 100;
- }
- }
+ public Modules Modules { get; internal set; }
+ public double Covered { get; internal set; }
+ public int Total { get; internal set; }
+ public double Percent
+ {
+ get
+ {
+ if (Modules?.Count == 0) return 0;
+ return Total == 0 ? 100D : Math.Floor((Covered / Total) * 10000) / 100;
+ }
+ }
- public double AverageModulePercent
- {
- get { return Math.Floor(_averageModulePercent * 100) / 100; }
- internal set { _averageModulePercent = value; }
- }
+ public double AverageModulePercent
+ {
+ get { return Math.Floor(_averageModulePercent * 100) / 100; }
+ internal set { _averageModulePercent = value; }
}
-}
\ No newline at end of file
+ }
+}
diff --git a/src/coverlet.core/CoveragePrepareResult.cs b/src/coverlet.core/CoveragePrepareResult.cs
index 7c15d76c3..ecfd234cf 100644
--- a/src/coverlet.core/CoveragePrepareResult.cs
+++ b/src/coverlet.core/CoveragePrepareResult.cs
@@ -7,36 +7,36 @@
namespace Coverlet.Core
{
- // Followed safe serializer guide, will emit xml format
- // https://docs.microsoft.com/en-us/visualstudio/code-quality/ca2300-do-not-use-insecure-deserializer-binaryformatter?view=vs-2019
- // https://docs.microsoft.com/en-us/visualstudio/code-quality/ca2301-do-not-call-binaryformatter-deserialize-without-first-setting-binaryformatter-binder?view=vs-2019
- [DataContract]
- internal class CoveragePrepareResult
- {
- [DataMember]
- public string Identifier { get; set; }
- [DataMember]
- public string ModuleOrDirectory { get; set; }
- [DataMember]
- public string MergeWith { get; set; }
- [DataMember]
- public bool UseSourceLink { get; set; }
- [DataMember]
- public InstrumenterResult[] Results { get; set; }
- [DataMember]
- public CoverageParameters Parameters { get; set; }
+ // Followed safe serializer guide, will emit xml format
+ // https://docs.microsoft.com/en-us/visualstudio/code-quality/ca2300-do-not-use-insecure-deserializer-binaryformatter?view=vs-2019
+ // https://docs.microsoft.com/en-us/visualstudio/code-quality/ca2301-do-not-call-binaryformatter-deserialize-without-first-setting-binaryformatter-binder?view=vs-2019
+ [DataContract]
+ internal class CoveragePrepareResult
+ {
+ [DataMember]
+ public string Identifier { get; set; }
+ [DataMember]
+ public string ModuleOrDirectory { get; set; }
+ [DataMember]
+ public string MergeWith { get; set; }
+ [DataMember]
+ public bool UseSourceLink { get; set; }
+ [DataMember]
+ public InstrumenterResult[] Results { get; set; }
+ [DataMember]
+ public CoverageParameters Parameters { get; set; }
- public static CoveragePrepareResult Deserialize(Stream serializedInstrumentState)
- {
- return (CoveragePrepareResult)new DataContractSerializer(typeof(CoveragePrepareResult)).ReadObject(serializedInstrumentState);
- }
+ public static CoveragePrepareResult Deserialize(Stream serializedInstrumentState)
+ {
+ return (CoveragePrepareResult)new DataContractSerializer(typeof(CoveragePrepareResult)).ReadObject(serializedInstrumentState);
+ }
- public static Stream Serialize(CoveragePrepareResult instrumentState)
- {
- var ms = new MemoryStream();
- new DataContractSerializer(typeof(CoveragePrepareResult)).WriteObject(ms, instrumentState);
- ms.Position = 0;
- return ms;
- }
+ public static Stream Serialize(CoveragePrepareResult instrumentState)
+ {
+ var ms = new MemoryStream();
+ new DataContractSerializer(typeof(CoveragePrepareResult)).WriteObject(ms, instrumentState);
+ ms.Position = 0;
+ return ms;
}
+ }
}
diff --git a/src/coverlet.core/CoverageSummary.cs b/src/coverlet.core/CoverageSummary.cs
index a56cda454..34370074b 100644
--- a/src/coverlet.core/CoverageSummary.cs
+++ b/src/coverlet.core/CoverageSummary.cs
@@ -7,270 +7,270 @@
namespace Coverlet.Core
{
- internal class CoverageSummary
+ internal class CoverageSummary
+ {
+ public CoverageDetails CalculateLineCoverage(Lines lines)
{
- public CoverageDetails CalculateLineCoverage(Lines lines)
- {
- var details = new CoverageDetails();
- details.Covered = lines.Where(l => l.Value > 0).Count();
- details.Total = lines.Count;
- return details;
- }
+ var details = new CoverageDetails();
+ details.Covered = lines.Where(l => l.Value > 0).Count();
+ details.Total = lines.Count;
+ return details;
+ }
- public CoverageDetails CalculateLineCoverage(Methods methods)
- {
- var details = new CoverageDetails();
- foreach (KeyValuePair method in methods)
- {
- CoverageDetails methodCoverage = CalculateLineCoverage(method.Value.Lines);
- details.Covered += methodCoverage.Covered;
- details.Total += methodCoverage.Total;
- }
- return details;
- }
+ public CoverageDetails CalculateLineCoverage(Methods methods)
+ {
+ var details = new CoverageDetails();
+ foreach (KeyValuePair method in methods)
+ {
+ CoverageDetails methodCoverage = CalculateLineCoverage(method.Value.Lines);
+ details.Covered += methodCoverage.Covered;
+ details.Total += methodCoverage.Total;
+ }
+ return details;
+ }
- public CoverageDetails CalculateLineCoverage(Classes classes)
- {
- var details = new CoverageDetails();
- foreach (KeyValuePair @class in classes)
- {
- CoverageDetails classCoverage = CalculateLineCoverage(@class.Value);
- details.Covered += classCoverage.Covered;
- details.Total += classCoverage.Total;
- }
- return details;
- }
+ public CoverageDetails CalculateLineCoverage(Classes classes)
+ {
+ var details = new CoverageDetails();
+ foreach (KeyValuePair @class in classes)
+ {
+ CoverageDetails classCoverage = CalculateLineCoverage(@class.Value);
+ details.Covered += classCoverage.Covered;
+ details.Total += classCoverage.Total;
+ }
+ return details;
+ }
- public CoverageDetails CalculateLineCoverage(Documents documents)
- {
- var details = new CoverageDetails();
- foreach (KeyValuePair document in documents)
- {
- CoverageDetails documentCoverage = CalculateLineCoverage(document.Value);
- details.Covered += documentCoverage.Covered;
- details.Total += documentCoverage.Total;
- }
- return details;
- }
+ public CoverageDetails CalculateLineCoverage(Documents documents)
+ {
+ var details = new CoverageDetails();
+ foreach (KeyValuePair document in documents)
+ {
+ CoverageDetails documentCoverage = CalculateLineCoverage(document.Value);
+ details.Covered += documentCoverage.Covered;
+ details.Total += documentCoverage.Total;
+ }
+ return details;
+ }
- public CoverageDetails CalculateLineCoverage(Modules modules)
- {
- var details = new CoverageDetails { Modules = modules };
- double accumPercent = 0.0D;
-
- if (modules.Count == 0)
- return details;
-
- foreach (KeyValuePair module in modules)
- {
- CoverageDetails moduleCoverage = CalculateLineCoverage(module.Value);
- details.Covered += moduleCoverage.Covered;
- details.Total += moduleCoverage.Total;
- accumPercent += moduleCoverage.Percent;
- }
- details.AverageModulePercent = accumPercent / modules.Count;
- return details;
- }
+ public CoverageDetails CalculateLineCoverage(Modules modules)
+ {
+ var details = new CoverageDetails { Modules = modules };
+ double accumPercent = 0.0D;
+
+ if (modules.Count == 0)
+ return details;
+
+ foreach (KeyValuePair module in modules)
+ {
+ CoverageDetails moduleCoverage = CalculateLineCoverage(module.Value);
+ details.Covered += moduleCoverage.Covered;
+ details.Total += moduleCoverage.Total;
+ accumPercent += moduleCoverage.Percent;
+ }
+ details.AverageModulePercent = accumPercent / modules.Count;
+ return details;
+ }
- public CoverageDetails CalculateBranchCoverage(IList branches)
- {
- var details = new CoverageDetails();
- details.Covered = branches.Count(bi => bi.Hits > 0);
- details.Total = branches.Count;
- return details;
- }
+ public CoverageDetails CalculateBranchCoverage(IList branches)
+ {
+ var details = new CoverageDetails();
+ details.Covered = branches.Count(bi => bi.Hits > 0);
+ details.Total = branches.Count;
+ return details;
+ }
- public int CalculateNpathComplexity(IList branches)
+ public int CalculateNpathComplexity(IList branches)
+ {
+ // Adapted from OpenCover see https://github.com/OpenCover/opencover/blob/master/main/OpenCover.Framework/Persistance/BasePersistance.cs#L419
+ if (!branches.Any())
+ {
+ return 0;
+ }
+
+ var paths = new Dictionary();
+ foreach (BranchInfo branch in branches)
+ {
+ if (!paths.TryGetValue(branch.Offset, out int count))
{
- // Adapted from OpenCover see https://github.com/OpenCover/opencover/blob/master/main/OpenCover.Framework/Persistance/BasePersistance.cs#L419
- if (!branches.Any())
- {
- return 0;
- }
-
- var paths = new Dictionary();
- foreach (BranchInfo branch in branches)
- {
- if (!paths.TryGetValue(branch.Offset, out int count))
- {
- count = 0;
- }
- paths[branch.Offset] = ++count;
- }
-
- int npath = 1;
- foreach (int branchPoints in paths.Values)
- {
- try
- {
- npath = checked(npath * branchPoints);
- }
- catch (OverflowException)
- {
- npath = int.MaxValue;
- break;
- }
- }
- return npath;
+ count = 0;
}
+ paths[branch.Offset] = ++count;
+ }
- public int CalculateCyclomaticComplexity(IList branches)
+ int npath = 1;
+ foreach (int branchPoints in paths.Values)
+ {
+ try
{
- return Math.Max(1, branches.Count);
+ npath = checked(npath * branchPoints);
}
-
- public int CalculateCyclomaticComplexity(Methods methods)
+ catch (OverflowException)
{
- return methods.Values.Select(m => CalculateCyclomaticComplexity(m.Branches)).Sum();
+ npath = int.MaxValue;
+ break;
}
+ }
+ return npath;
+ }
- public int CalculateMaxCyclomaticComplexity(Methods methods)
- {
- return methods.Values.Select(m => CalculateCyclomaticComplexity(m.Branches)).DefaultIfEmpty(1).Max();
- }
+ public int CalculateCyclomaticComplexity(IList branches)
+ {
+ return Math.Max(1, branches.Count);
+ }
- public int CalculateMinCyclomaticComplexity(Methods methods)
- {
- return methods.Values.Select(m => CalculateCyclomaticComplexity(m.Branches)).DefaultIfEmpty(1).Min();
- }
+ public int CalculateCyclomaticComplexity(Methods methods)
+ {
+ return methods.Values.Select(m => CalculateCyclomaticComplexity(m.Branches)).Sum();
+ }
- public int CalculateCyclomaticComplexity(Modules modules)
- {
- return modules.Values.Select(CalculateCyclomaticComplexity).Sum();
- }
+ public int CalculateMaxCyclomaticComplexity(Methods methods)
+ {
+ return methods.Values.Select(m => CalculateCyclomaticComplexity(m.Branches)).DefaultIfEmpty(1).Max();
+ }
- public int CalculateMaxCyclomaticComplexity(Modules modules)
- {
- return modules.Values.Select(CalculateCyclomaticComplexity).DefaultIfEmpty(1).Max();
- }
+ public int CalculateMinCyclomaticComplexity(Methods methods)
+ {
+ return methods.Values.Select(m => CalculateCyclomaticComplexity(m.Branches)).DefaultIfEmpty(1).Min();
+ }
- public int CalculateMinCyclomaticComplexity(Modules modules)
- {
- return modules.Values.Select(CalculateCyclomaticComplexity).DefaultIfEmpty(1).Min();
- }
+ public int CalculateCyclomaticComplexity(Modules modules)
+ {
+ return modules.Values.Select(CalculateCyclomaticComplexity).Sum();
+ }
- public int CalculateCyclomaticComplexity(Documents documents)
- {
- return documents.Values.SelectMany(c => c.Values.Select(CalculateCyclomaticComplexity)).Sum();
- }
+ public int CalculateMaxCyclomaticComplexity(Modules modules)
+ {
+ return modules.Values.Select(CalculateCyclomaticComplexity).DefaultIfEmpty(1).Max();
+ }
- public CoverageDetails CalculateBranchCoverage(Methods methods)
- {
- var details = new CoverageDetails();
- foreach (KeyValuePair method in methods)
- {
- CoverageDetails methodCoverage = CalculateBranchCoverage(method.Value.Branches);
- details.Covered += methodCoverage.Covered;
- details.Total += methodCoverage.Total;
- }
- return details;
- }
+ public int CalculateMinCyclomaticComplexity(Modules modules)
+ {
+ return modules.Values.Select(CalculateCyclomaticComplexity).DefaultIfEmpty(1).Min();
+ }
- public CoverageDetails CalculateBranchCoverage(Classes classes)
- {
- var details = new CoverageDetails();
- foreach (KeyValuePair @class in classes)
- {
- CoverageDetails classCoverage = CalculateBranchCoverage(@class.Value);
- details.Covered += classCoverage.Covered;
- details.Total += classCoverage.Total;
- }
- return details;
- }
+ public int CalculateCyclomaticComplexity(Documents documents)
+ {
+ return documents.Values.SelectMany(c => c.Values.Select(CalculateCyclomaticComplexity)).Sum();
+ }
- public CoverageDetails CalculateBranchCoverage(Documents documents)
- {
- var details = new CoverageDetails();
- foreach (KeyValuePair document in documents)
- {
- CoverageDetails documentCoverage = CalculateBranchCoverage(document.Value);
- details.Covered += documentCoverage.Covered;
- details.Total += documentCoverage.Total;
- }
- return details;
- }
+ public CoverageDetails CalculateBranchCoverage(Methods methods)
+ {
+ var details = new CoverageDetails();
+ foreach (KeyValuePair method in methods)
+ {
+ CoverageDetails methodCoverage = CalculateBranchCoverage(method.Value.Branches);
+ details.Covered += methodCoverage.Covered;
+ details.Total += methodCoverage.Total;
+ }
+ return details;
+ }
- public CoverageDetails CalculateBranchCoverage(Modules modules)
- {
- var details = new CoverageDetails { Modules = modules };
- double accumPercent = 0.0D;
-
- if (modules.Count == 0)
- return details;
-
- foreach (KeyValuePair module in modules)
- {
- CoverageDetails moduleCoverage = CalculateBranchCoverage(module.Value);
- details.Covered += moduleCoverage.Covered;
- details.Total += moduleCoverage.Total;
- accumPercent += moduleCoverage.Percent;
- }
- details.AverageModulePercent = modules.Count == 0 ? 0 : accumPercent / modules.Count;
- return details;
- }
+ public CoverageDetails CalculateBranchCoverage(Classes classes)
+ {
+ var details = new CoverageDetails();
+ foreach (KeyValuePair @class in classes)
+ {
+ CoverageDetails classCoverage = CalculateBranchCoverage(@class.Value);
+ details.Covered += classCoverage.Covered;
+ details.Total += classCoverage.Total;
+ }
+ return details;
+ }
- public CoverageDetails CalculateMethodCoverage(Lines lines)
- {
- var details = new CoverageDetails();
- details.Covered = lines.Any(l => l.Value > 0) ? 1 : 0;
- details.Total = 1;
- return details;
- }
+ public CoverageDetails CalculateBranchCoverage(Documents documents)
+ {
+ var details = new CoverageDetails();
+ foreach (KeyValuePair document in documents)
+ {
+ CoverageDetails documentCoverage = CalculateBranchCoverage(document.Value);
+ details.Covered += documentCoverage.Covered;
+ details.Total += documentCoverage.Total;
+ }
+ return details;
+ }
- public CoverageDetails CalculateMethodCoverage(Methods methods)
- {
- var details = new CoverageDetails();
- IEnumerable> methodsWithLines = methods.Where(m => m.Value.Lines.Count > 0);
- foreach (KeyValuePair method in methodsWithLines)
- {
- CoverageDetails methodCoverage = CalculateMethodCoverage(method.Value.Lines);
- details.Covered += methodCoverage.Covered;
- }
- details.Total = methodsWithLines.Count();
- return details;
- }
+ public CoverageDetails CalculateBranchCoverage(Modules modules)
+ {
+ var details = new CoverageDetails { Modules = modules };
+ double accumPercent = 0.0D;
+
+ if (modules.Count == 0)
+ return details;
+
+ foreach (KeyValuePair module in modules)
+ {
+ CoverageDetails moduleCoverage = CalculateBranchCoverage(module.Value);
+ details.Covered += moduleCoverage.Covered;
+ details.Total += moduleCoverage.Total;
+ accumPercent += moduleCoverage.Percent;
+ }
+ details.AverageModulePercent = modules.Count == 0 ? 0 : accumPercent / modules.Count;
+ return details;
+ }
- public CoverageDetails CalculateMethodCoverage(Classes classes)
- {
- var details = new CoverageDetails();
- foreach (KeyValuePair @class in classes)
- {
- CoverageDetails classCoverage = CalculateMethodCoverage(@class.Value);
- details.Covered += classCoverage.Covered;
- details.Total += classCoverage.Total;
- }
- return details;
- }
+ public CoverageDetails CalculateMethodCoverage(Lines lines)
+ {
+ var details = new CoverageDetails();
+ details.Covered = lines.Any(l => l.Value > 0) ? 1 : 0;
+ details.Total = 1;
+ return details;
+ }
- public CoverageDetails CalculateMethodCoverage(Documents documents)
- {
- var details = new CoverageDetails();
- foreach (KeyValuePair document in documents)
- {
- CoverageDetails documentCoverage = CalculateMethodCoverage(document.Value);
- details.Covered += documentCoverage.Covered;
- details.Total += documentCoverage.Total;
- }
- return details;
- }
+ public CoverageDetails CalculateMethodCoverage(Methods methods)
+ {
+ var details = new CoverageDetails();
+ IEnumerable> methodsWithLines = methods.Where(m => m.Value.Lines.Count > 0);
+ foreach (KeyValuePair method in methodsWithLines)
+ {
+ CoverageDetails methodCoverage = CalculateMethodCoverage(method.Value.Lines);
+ details.Covered += methodCoverage.Covered;
+ }
+ details.Total = methodsWithLines.Count();
+ return details;
+ }
- public CoverageDetails CalculateMethodCoverage(Modules modules)
- {
- var details = new CoverageDetails { Modules = modules };
- double accumPercent = 0.0D;
-
- if (modules.Count == 0)
- return details;
-
- foreach (KeyValuePair module in modules)
- {
- CoverageDetails moduleCoverage = CalculateMethodCoverage(module.Value);
- details.Covered += moduleCoverage.Covered;
- details.Total += moduleCoverage.Total;
- accumPercent += moduleCoverage.Percent;
- }
- details.AverageModulePercent = modules.Count == 0 ? 0 : accumPercent / modules.Count;
- return details;
- }
+ public CoverageDetails CalculateMethodCoverage(Classes classes)
+ {
+ var details = new CoverageDetails();
+ foreach (KeyValuePair @class in classes)
+ {
+ CoverageDetails classCoverage = CalculateMethodCoverage(@class.Value);
+ details.Covered += classCoverage.Covered;
+ details.Total += classCoverage.Total;
+ }
+ return details;
+ }
+
+ public CoverageDetails CalculateMethodCoverage(Documents documents)
+ {
+ var details = new CoverageDetails();
+ foreach (KeyValuePair document in documents)
+ {
+ CoverageDetails documentCoverage = CalculateMethodCoverage(document.Value);
+ details.Covered += documentCoverage.Covered;
+ details.Total += documentCoverage.Total;
+ }
+ return details;
+ }
+
+ public CoverageDetails CalculateMethodCoverage(Modules modules)
+ {
+ var details = new CoverageDetails { Modules = modules };
+ double accumPercent = 0.0D;
+
+ if (modules.Count == 0)
+ return details;
+
+ foreach (KeyValuePair module in modules)
+ {
+ CoverageDetails moduleCoverage = CalculateMethodCoverage(module.Value);
+ details.Covered += moduleCoverage.Covered;
+ details.Total += moduleCoverage.Total;
+ accumPercent += moduleCoverage.Percent;
+ }
+ details.AverageModulePercent = modules.Count == 0 ? 0 : accumPercent / modules.Count;
+ return details;
}
+ }
}
diff --git a/src/coverlet.core/Enums/AssemblySearchType.cs b/src/coverlet.core/Enums/AssemblySearchType.cs
index 099e54217..4eef8b96f 100644
--- a/src/coverlet.core/Enums/AssemblySearchType.cs
+++ b/src/coverlet.core/Enums/AssemblySearchType.cs
@@ -3,10 +3,10 @@
namespace Coverlet.Core.Enums
{
- internal enum AssemblySearchType
- {
- MissingAny,
- MissingAll,
- None
- }
+ internal enum AssemblySearchType
+ {
+ MissingAny,
+ MissingAll,
+ None
+ }
}
diff --git a/src/coverlet.core/Enums/ThresholdStatistic.cs b/src/coverlet.core/Enums/ThresholdStatistic.cs
index 1dbb55dc0..31aa72cd9 100644
--- a/src/coverlet.core/Enums/ThresholdStatistic.cs
+++ b/src/coverlet.core/Enums/ThresholdStatistic.cs
@@ -1,12 +1,12 @@
-// Copyright (c) Toni Solarin-Sodara
+// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Coverlet.Core.Enums
{
- internal enum ThresholdStatistic
- {
- Minimum,
- Average,
- Total
- }
-}
\ No newline at end of file
+ internal enum ThresholdStatistic
+ {
+ Minimum,
+ Average,
+ Total
+ }
+}
diff --git a/src/coverlet.core/Enums/ThresholdTypeFlags.cs b/src/coverlet.core/Enums/ThresholdTypeFlags.cs
index 9b24222a5..2463fab9a 100644
--- a/src/coverlet.core/Enums/ThresholdTypeFlags.cs
+++ b/src/coverlet.core/Enums/ThresholdTypeFlags.cs
@@ -1,16 +1,16 @@
-// Copyright (c) Toni Solarin-Sodara
+// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
namespace Coverlet.Core.Enums
{
- [Flags]
- internal enum ThresholdTypeFlags
- {
- None = 0,
- Line = 2,
- Branch = 4,
- Method = 8
- }
-}
\ No newline at end of file
+ [Flags]
+ internal enum ThresholdTypeFlags
+ {
+ None = 0,
+ Line = 2,
+ Branch = 4,
+ Method = 8
+ }
+}
diff --git a/src/coverlet.core/Exceptions.cs b/src/coverlet.core/Exceptions.cs
index 8b97ca283..d65b22096 100644
--- a/src/coverlet.core/Exceptions.cs
+++ b/src/coverlet.core/Exceptions.cs
@@ -5,25 +5,25 @@
namespace Coverlet.Core.Exceptions
{
- [Serializable]
- public class CoverletException : Exception
- {
- public CoverletException() { }
- public CoverletException(string message) : base(message) { }
- public CoverletException(string message, System.Exception inner) : base(message, inner) { }
- protected CoverletException(
- System.Runtime.Serialization.SerializationInfo info,
- System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
- }
+ [Serializable]
+ public class CoverletException : Exception
+ {
+ public CoverletException() { }
+ public CoverletException(string message) : base(message) { }
+ public CoverletException(string message, System.Exception inner) : base(message, inner) { }
+ protected CoverletException(
+ System.Runtime.Serialization.SerializationInfo info,
+ System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
+ }
- [Serializable]
- internal class CecilAssemblyResolutionException : CoverletException
- {
- public CecilAssemblyResolutionException() { }
- public CecilAssemblyResolutionException(string message) : base(message) { }
- public CecilAssemblyResolutionException(string message, System.Exception inner) : base(message, inner) { }
- protected CecilAssemblyResolutionException(
- System.Runtime.Serialization.SerializationInfo info,
- System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
- }
+ [Serializable]
+ internal class CecilAssemblyResolutionException : CoverletException
+ {
+ public CecilAssemblyResolutionException() { }
+ public CecilAssemblyResolutionException(string message) : base(message) { }
+ public CecilAssemblyResolutionException(string message, System.Exception inner) : base(message, inner) { }
+ protected CecilAssemblyResolutionException(
+ System.Runtime.Serialization.SerializationInfo info,
+ System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
+ }
}
diff --git a/src/coverlet.core/Extensions/HelperExtensions.cs b/src/coverlet.core/Extensions/HelperExtensions.cs
index 30439c0c9..191e9cc38 100644
--- a/src/coverlet.core/Extensions/HelperExtensions.cs
+++ b/src/coverlet.core/Extensions/HelperExtensions.cs
@@ -6,13 +6,13 @@
namespace Coverlet.Core.Extensions
{
- internal static class HelperExtensions
+ internal static class HelperExtensions
+ {
+ [ExcludeFromCoverage]
+ public static TRet Maybe(this T value, Func action, TRet defValue = default)
+ where T : class
{
- [ExcludeFromCoverage]
- public static TRet Maybe(this T value, Func action, TRet defValue = default)
- where T : class
- {
- return (value != null) ? action(value) : defValue;
- }
+ return (value != null) ? action(value) : defValue;
}
+ }
}
diff --git a/src/coverlet.core/Helpers/AssemblyAdapter.cs b/src/coverlet.core/Helpers/AssemblyAdapter.cs
index f4626d2ff..124c11a9f 100644
--- a/src/coverlet.core/Helpers/AssemblyAdapter.cs
+++ b/src/coverlet.core/Helpers/AssemblyAdapter.cs
@@ -6,11 +6,11 @@
namespace Coverlet.Core.Helpers
{
- internal class AssemblyAdapter : IAssemblyAdapter
+ internal class AssemblyAdapter : IAssemblyAdapter
+ {
+ public string GetAssemblyName(string assemblyPath)
{
- public string GetAssemblyName(string assemblyPath)
- {
- return AssemblyName.GetAssemblyName(assemblyPath).Name;
- }
+ return AssemblyName.GetAssemblyName(assemblyPath).Name;
}
+ }
}
diff --git a/src/coverlet.core/Helpers/Console.cs b/src/coverlet.core/Helpers/Console.cs
index 8781b49de..4652a194a 100644
--- a/src/coverlet.core/Helpers/Console.cs
+++ b/src/coverlet.core/Helpers/Console.cs
@@ -6,11 +6,11 @@
namespace Coverlet.Core.Helpers
{
- public class SystemConsole : IConsole
+ public class SystemConsole : IConsole
+ {
+ public void WriteLine(string value)
{
- public void WriteLine(string value)
- {
- Console.WriteLine(value);
- }
+ Console.WriteLine(value);
}
+ }
}
diff --git a/src/coverlet.core/Helpers/FileSystem.cs b/src/coverlet.core/Helpers/FileSystem.cs
index 10dfc8f0a..e8af5b947 100644
--- a/src/coverlet.core/Helpers/FileSystem.cs
+++ b/src/coverlet.core/Helpers/FileSystem.cs
@@ -6,61 +6,61 @@
namespace Coverlet.Core.Helpers
{
- internal class FileSystem : IFileSystem
+ internal class FileSystem : IFileSystem
+ {
+ // We need to partial mock this method on tests
+ public virtual bool Exists(string path)
{
- // We need to partial mock this method on tests
- public virtual bool Exists(string path)
- {
- return File.Exists(path);
- }
+ return File.Exists(path);
+ }
- public void WriteAllText(string path, string contents)
- {
- File.WriteAllText(path, contents);
- }
+ public void WriteAllText(string path, string contents)
+ {
+ File.WriteAllText(path, contents);
+ }
- public string ReadAllText(string path)
- {
- return File.ReadAllText(path);
- }
+ public string ReadAllText(string path)
+ {
+ return File.ReadAllText(path);
+ }
- // We need to partial mock this method on tests
- public virtual Stream OpenRead(string path)
- {
- return File.OpenRead(path);
- }
+ // We need to partial mock this method on tests
+ public virtual Stream OpenRead(string path)
+ {
+ return File.OpenRead(path);
+ }
- public void Copy(string sourceFileName, string destFileName, bool overwrite)
- {
- File.Copy(sourceFileName, destFileName, overwrite);
- }
+ public void Copy(string sourceFileName, string destFileName, bool overwrite)
+ {
+ File.Copy(sourceFileName, destFileName, overwrite);
+ }
- public void Delete(string path)
- {
- File.Delete(path);
- }
+ public void Delete(string path)
+ {
+ File.Delete(path);
+ }
- // We need to partial mock this method on tests
- public virtual Stream NewFileStream(string path, FileMode mode)
- {
- return new FileStream(path, mode);
- }
+ // We need to partial mock this method on tests
+ public virtual Stream NewFileStream(string path, FileMode mode)
+ {
+ return new FileStream(path, mode);
+ }
- // We need to partial mock this method on tests
- public virtual Stream NewFileStream(string path, FileMode mode, FileAccess access)
- {
- return new FileStream(path, mode, access);
- }
+ // We need to partial mock this method on tests
+ public virtual Stream NewFileStream(string path, FileMode mode, FileAccess access)
+ {
+ return new FileStream(path, mode, access);
+ }
- public string[] ReadAllLines(string path)
- {
- return File.ReadAllLines(path);
- }
+ public string[] ReadAllLines(string path)
+ {
+ return File.ReadAllLines(path);
+ }
- // Escape format characters in file names
- internal static string EscapeFileName(string fileName)
- {
- return fileName?.Replace("{", "{{").Replace("}", "}}");
- }
+ // Escape format characters in file names
+ internal static string EscapeFileName(string fileName)
+ {
+ return fileName?.Replace("{", "{{").Replace("}", "}}");
}
+ }
}
diff --git a/src/coverlet.core/Helpers/InstrumentationHelper.cs b/src/coverlet.core/Helpers/InstrumentationHelper.cs
index 6723fc733..1221353e3 100644
--- a/src/coverlet.core/Helpers/InstrumentationHelper.cs
+++ b/src/coverlet.core/Helpers/InstrumentationHelper.cs
@@ -16,477 +16,477 @@
namespace Coverlet.Core.Helpers
{
- internal class InstrumentationHelper : IInstrumentationHelper
+ internal class InstrumentationHelper : IInstrumentationHelper
+ {
+ private const int RetryAttempts = 12;
+ private readonly ConcurrentDictionary _backupList = new();
+ private readonly IRetryHelper _retryHelper;
+ private readonly IFileSystem _fileSystem;
+ private readonly ISourceRootTranslator _sourceRootTranslator;
+ private ILogger _logger;
+
+ public InstrumentationHelper(IProcessExitHandler processExitHandler, IRetryHelper retryHelper, IFileSystem fileSystem, ILogger logger, ISourceRootTranslator sourceRootTranslator)
{
- private const int RetryAttempts = 12;
- private readonly ConcurrentDictionary _backupList = new();
- private readonly IRetryHelper _retryHelper;
- private readonly IFileSystem _fileSystem;
- private readonly ISourceRootTranslator _sourceRootTranslator;
- private ILogger _logger;
-
- public InstrumentationHelper(IProcessExitHandler processExitHandler, IRetryHelper retryHelper, IFileSystem fileSystem, ILogger logger, ISourceRootTranslator sourceRootTranslator)
- {
- processExitHandler.Add((s, e) => RestoreOriginalModules());
- _retryHelper = retryHelper;
- _fileSystem = fileSystem;
- _logger = logger;
- _sourceRootTranslator = sourceRootTranslator;
- }
+ processExitHandler.Add((s, e) => RestoreOriginalModules());
+ _retryHelper = retryHelper;
+ _fileSystem = fileSystem;
+ _logger = logger;
+ _sourceRootTranslator = sourceRootTranslator;
+ }
- public string[] GetCoverableModules(string moduleOrAppDirectory, string[] directories, bool includeTestAssembly)
- {
- Debug.Assert(directories != null);
- Debug.Assert(moduleOrAppDirectory != null);
+ public string[] GetCoverableModules(string moduleOrAppDirectory, string[] directories, bool includeTestAssembly)
+ {
+ Debug.Assert(directories != null);
+ Debug.Assert(moduleOrAppDirectory != null);
- bool isAppDirectory = !File.Exists(moduleOrAppDirectory) && Directory.Exists(moduleOrAppDirectory);
- string moduleDirectory = isAppDirectory ? moduleOrAppDirectory : Path.GetDirectoryName(moduleOrAppDirectory);
+ bool isAppDirectory = !File.Exists(moduleOrAppDirectory) && Directory.Exists(moduleOrAppDirectory);
+ string moduleDirectory = isAppDirectory ? moduleOrAppDirectory : Path.GetDirectoryName(moduleOrAppDirectory);
- if (moduleDirectory == string.Empty)
- {
- moduleDirectory = Directory.GetCurrentDirectory();
- }
+ if (moduleDirectory == string.Empty)
+ {
+ moduleDirectory = Directory.GetCurrentDirectory();
+ }
- var dirs = new List()
+ var dirs = new List()
{
// Add the test assembly's directory.
moduleDirectory
};
- // Prepare all the directories we probe for modules.
- foreach (string directory in directories)
- {
- if (string.IsNullOrWhiteSpace(directory)) continue;
+ // Prepare all the directories we probe for modules.
+ foreach (string directory in directories)
+ {
+ if (string.IsNullOrWhiteSpace(directory)) continue;
- string fullPath = (!Path.IsPathRooted(directory)
- ? Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), directory))
- : directory).TrimEnd('*');
+ string fullPath = (!Path.IsPathRooted(directory)
+ ? Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), directory))
+ : directory).TrimEnd('*');
- if (!Directory.Exists(fullPath)) continue;
+ if (!Directory.Exists(fullPath)) continue;
- if (directory.EndsWith("*", StringComparison.Ordinal))
- dirs.AddRange(Directory.GetDirectories(fullPath));
- else
- dirs.Add(fullPath);
- }
+ if (directory.EndsWith("*", StringComparison.Ordinal))
+ dirs.AddRange(Directory.GetDirectories(fullPath));
+ else
+ dirs.Add(fullPath);
+ }
- // The module's name must be unique.
- var uniqueModules = new HashSet();
+ // The module's name must be unique.
+ var uniqueModules = new HashSet();
- if (!includeTestAssembly && !isAppDirectory)
- uniqueModules.Add(Path.GetFileName(moduleOrAppDirectory));
+ if (!includeTestAssembly && !isAppDirectory)
+ uniqueModules.Add(Path.GetFileName(moduleOrAppDirectory));
- return dirs.SelectMany(d => Directory.EnumerateFiles(d))
- .Where(m => IsAssembly(m) && uniqueModules.Add(Path.GetFileName(m)))
- .ToArray();
- }
+ return dirs.SelectMany(d => Directory.EnumerateFiles(d))
+ .Where(m => IsAssembly(m) && uniqueModules.Add(Path.GetFileName(m)))
+ .ToArray();
+ }
- public bool HasPdb(string module, out bool embedded)
+ public bool HasPdb(string module, out bool embedded)
+ {
+ embedded = false;
+ using Stream moduleStream = _fileSystem.OpenRead(module);
+ using var peReader = new PEReader(moduleStream);
+ foreach (DebugDirectoryEntry entry in peReader.ReadDebugDirectory())
+ {
+ if (entry.Type == DebugDirectoryEntryType.CodeView)
{
+ CodeViewDebugDirectoryData codeViewData = peReader.ReadCodeViewDebugDirectoryData(entry);
+ string modulePdbFileName = $"{Path.GetFileNameWithoutExtension(module)}.pdb";
+ if (_sourceRootTranslator.ResolveFilePath(codeViewData.Path) == modulePdbFileName)
+ {
+ // PDB is embedded
+ embedded = true;
+ return true;
+ }
+
+ if (_fileSystem.Exists(_sourceRootTranslator.ResolveFilePath(codeViewData.Path)))
+ {
+ // local PDB is located within original build location
embedded = false;
- using Stream moduleStream = _fileSystem.OpenRead(module);
- using var peReader = new PEReader(moduleStream);
- foreach (DebugDirectoryEntry entry in peReader.ReadDebugDirectory())
- {
- if (entry.Type == DebugDirectoryEntryType.CodeView)
- {
- CodeViewDebugDirectoryData codeViewData = peReader.ReadCodeViewDebugDirectoryData(entry);
- string modulePdbFileName = $"{Path.GetFileNameWithoutExtension(module)}.pdb";
- if (_sourceRootTranslator.ResolveFilePath(codeViewData.Path) == modulePdbFileName)
- {
- // PDB is embedded
- embedded = true;
- return true;
- }
-
- if (_fileSystem.Exists(_sourceRootTranslator.ResolveFilePath(codeViewData.Path)))
- {
- // local PDB is located within original build location
- embedded = false;
- return true;
- }
-
- string localPdbFileName = Path.Combine(Path.GetDirectoryName(module), modulePdbFileName);
- if (_fileSystem.Exists(localPdbFileName))
- {
- // local PDB is located within same folder as module
- embedded = false;
-
- // mapping need to be registered in _sourceRootTranslator to use that discovery
- _sourceRootTranslator.AddMappingInCache(codeViewData.Path, localPdbFileName);
-
- return true;
- }
- }
- }
+ return true;
+ }
- return false;
- }
+ string localPdbFileName = Path.Combine(Path.GetDirectoryName(module), modulePdbFileName);
+ if (_fileSystem.Exists(localPdbFileName))
+ {
+ // local PDB is located within same folder as module
+ embedded = false;
+
+ // mapping need to be registered in _sourceRootTranslator to use that discovery
+ _sourceRootTranslator.AddMappingInCache(codeViewData.Path, localPdbFileName);
- public bool EmbeddedPortablePdbHasLocalSource(string module, AssemblySearchType excludeAssembliesWithoutSources)
- {
- using Stream moduleStream = _fileSystem.OpenRead(module);
- using var peReader = new PEReader(moduleStream);
- foreach (DebugDirectoryEntry entry in peReader.ReadDebugDirectory())
- {
- if (entry.Type == DebugDirectoryEntryType.EmbeddedPortablePdb)
- {
- using MetadataReaderProvider embeddedMetadataProvider = peReader.ReadEmbeddedPortablePdbDebugDirectoryData(entry);
- MetadataReader metadataReader = embeddedMetadataProvider.GetMetadataReader();
-
- if (!MatchDocumentsWithSources(module, excludeAssembliesWithoutSources, metadataReader))
- {
- return false;
- }
- }
- }
-
- // If we don't have EmbeddedPortablePdb entry return true, for instance empty dll
- // We should call this method only on embedded pdb module
return true;
+ }
}
+ }
- public bool PortablePdbHasLocalSource(string module, AssemblySearchType excludeAssembliesWithoutSources)
+ return false;
+ }
+
+ public bool EmbeddedPortablePdbHasLocalSource(string module, AssemblySearchType excludeAssembliesWithoutSources)
+ {
+ using Stream moduleStream = _fileSystem.OpenRead(module);
+ using var peReader = new PEReader(moduleStream);
+ foreach (DebugDirectoryEntry entry in peReader.ReadDebugDirectory())
+ {
+ if (entry.Type == DebugDirectoryEntryType.EmbeddedPortablePdb)
{
- using Stream moduleStream = _fileSystem.OpenRead(module);
- using var peReader = new PEReader(moduleStream);
- foreach (DebugDirectoryEntry entry in peReader.ReadDebugDirectory())
- {
- if (entry.Type == DebugDirectoryEntryType.CodeView)
- {
- CodeViewDebugDirectoryData codeViewData = peReader.ReadCodeViewDebugDirectoryData(entry);
- using Stream pdbStream = _fileSystem.OpenRead(_sourceRootTranslator.ResolveFilePath(codeViewData.Path));
- using var metadataReaderProvider = MetadataReaderProvider.FromPortablePdbStream(pdbStream);
- MetadataReader metadataReader = null;
- try
- {
- metadataReader = metadataReaderProvider.GetMetadataReader();
- }
- catch (BadImageFormatException)
- {
- _logger.LogWarning($"{nameof(BadImageFormatException)} during MetadataReaderProvider.FromPortablePdbStream in InstrumentationHelper.PortablePdbHasLocalSource, unable to check if module has got local source.");
- return true;
- }
-
- if (!MatchDocumentsWithSources(module, excludeAssembliesWithoutSources, metadataReader))
- {
- return false;
- }
- }
- }
+ using MetadataReaderProvider embeddedMetadataProvider = peReader.ReadEmbeddedPortablePdbDebugDirectoryData(entry);
+ MetadataReader metadataReader = embeddedMetadataProvider.GetMetadataReader();
- return true;
+ if (!MatchDocumentsWithSources(module, excludeAssembliesWithoutSources, metadataReader))
+ {
+ return false;
+ }
}
+ }
- private bool MatchDocumentsWithSources(string module, AssemblySearchType excludeAssembliesWithoutSources,
- MetadataReader metadataReader)
- {
- if (excludeAssembliesWithoutSources.Equals(AssemblySearchType.MissingAll))
- {
- bool anyDocumentMatches = MatchDocumentsWithSourcesMissingAll(metadataReader);
- if (!anyDocumentMatches)
- {
- _logger.LogVerbose($"Excluding module from instrumentation: {module}, pdb without any local source files");
- return false;
- }
- }
-
- if (excludeAssembliesWithoutSources.Equals(AssemblySearchType.MissingAny))
- {
- (bool allDocumentsMatch, string notFoundDocument) = MatchDocumentsWithSourcesMissingAny(metadataReader);
-
- if (!allDocumentsMatch)
- {
- _logger.LogVerbose(
- $"Excluding module from instrumentation: {module}, pdb without local source files, [{FileSystem.EscapeFileName(notFoundDocument)}]");
- return false;
- }
- }
+ // If we don't have EmbeddedPortablePdb entry return true, for instance empty dll
+ // We should call this method only on embedded pdb module
+ return true;
+ }
+ public bool PortablePdbHasLocalSource(string module, AssemblySearchType excludeAssembliesWithoutSources)
+ {
+ using Stream moduleStream = _fileSystem.OpenRead(module);
+ using var peReader = new PEReader(moduleStream);
+ foreach (DebugDirectoryEntry entry in peReader.ReadDebugDirectory())
+ {
+ if (entry.Type == DebugDirectoryEntryType.CodeView)
+ {
+ CodeViewDebugDirectoryData codeViewData = peReader.ReadCodeViewDebugDirectoryData(entry);
+ using Stream pdbStream = _fileSystem.OpenRead(_sourceRootTranslator.ResolveFilePath(codeViewData.Path));
+ using var metadataReaderProvider = MetadataReaderProvider.FromPortablePdbStream(pdbStream);
+ MetadataReader metadataReader = null;
+ try
+ {
+ metadataReader = metadataReaderProvider.GetMetadataReader();
+ }
+ catch (BadImageFormatException)
+ {
+ _logger.LogWarning($"{nameof(BadImageFormatException)} during MetadataReaderProvider.FromPortablePdbStream in InstrumentationHelper.PortablePdbHasLocalSource, unable to check if module has got local source.");
return true;
- }
+ }
- private IEnumerable<(string documentName, bool documentExists)> DocumentSourceMap(MetadataReader metadataReader)
- {
- return metadataReader.Documents.Select(docHandle =>
- {
- Document document = metadataReader.GetDocument(docHandle);
- string docName = _sourceRootTranslator.ResolveFilePath(metadataReader.GetString(document.Name));
- return (docName, _fileSystem.Exists(docName));
- });
+ if (!MatchDocumentsWithSources(module, excludeAssembliesWithoutSources, metadataReader))
+ {
+ return false;
+ }
}
+ }
- private bool MatchDocumentsWithSourcesMissingAll(MetadataReader metadataReader)
- {
- return DocumentSourceMap(metadataReader).Any(x => x.documentExists);
- }
+ return true;
+ }
- private (bool allDocumentsMatch, string notFoundDocument) MatchDocumentsWithSourcesMissingAny(
- MetadataReader metadataReader)
+ private bool MatchDocumentsWithSources(string module, AssemblySearchType excludeAssembliesWithoutSources,
+ MetadataReader metadataReader)
+ {
+ if (excludeAssembliesWithoutSources.Equals(AssemblySearchType.MissingAll))
+ {
+ bool anyDocumentMatches = MatchDocumentsWithSourcesMissingAll(metadataReader);
+ if (!anyDocumentMatches)
{
- var documentSourceMap = DocumentSourceMap(metadataReader).ToList();
+ _logger.LogVerbose($"Excluding module from instrumentation: {module}, pdb without any local source files");
+ return false;
+ }
+ }
- if (documentSourceMap.Any(x => !x.documentExists))
- return (false, documentSourceMap.FirstOrDefault(x => !x.documentExists).documentName);
+ if (excludeAssembliesWithoutSources.Equals(AssemblySearchType.MissingAny))
+ {
+ (bool allDocumentsMatch, string notFoundDocument) = MatchDocumentsWithSourcesMissingAny(metadataReader);
- return (true, string.Empty);
+ if (!allDocumentsMatch)
+ {
+ _logger.LogVerbose(
+ $"Excluding module from instrumentation: {module}, pdb without local source files, [{FileSystem.EscapeFileName(notFoundDocument)}]");
+ return false;
}
+ }
- public void BackupOriginalModule(string module, string identifier)
- {
- string backupPath = GetBackupPath(module, identifier);
- string backupSymbolPath = Path.ChangeExtension(backupPath, ".pdb");
- _fileSystem.Copy(module, backupPath, true);
- if (!_backupList.TryAdd(module, backupPath))
- {
- throw new ArgumentException($"Key already added '{module}'");
- }
+ return true;
+ }
- string symbolFile = Path.ChangeExtension(module, ".pdb");
- if (_fileSystem.Exists(symbolFile))
- {
- _fileSystem.Copy(symbolFile, backupSymbolPath, true);
- if (!_backupList.TryAdd(symbolFile, backupSymbolPath))
- {
- throw new ArgumentException($"Key already added '{module}'");
- }
- }
- }
+ private IEnumerable<(string documentName, bool documentExists)> DocumentSourceMap(MetadataReader metadataReader)
+ {
+ return metadataReader.Documents.Select(docHandle =>
+ {
+ Document document = metadataReader.GetDocument(docHandle);
+ string docName = _sourceRootTranslator.ResolveFilePath(metadataReader.GetString(document.Name));
+ return (docName, _fileSystem.Exists(docName));
+ });
+ }
- public virtual void RestoreOriginalModule(string module, string identifier)
- {
- string backupPath = GetBackupPath(module, identifier);
- string backupSymbolPath = Path.ChangeExtension(backupPath, ".pdb");
+ private bool MatchDocumentsWithSourcesMissingAll(MetadataReader metadataReader)
+ {
+ return DocumentSourceMap(metadataReader).Any(x => x.documentExists);
+ }
- // Restore the original module - retry up to 10 times, since the destination file could be locked
- // See: https://github.com/tonerdo/coverlet/issues/25
- Func retryStrategy = CreateRetryStrategy();
+ private (bool allDocumentsMatch, string notFoundDocument) MatchDocumentsWithSourcesMissingAny(
+ MetadataReader metadataReader)
+ {
+ var documentSourceMap = DocumentSourceMap(metadataReader).ToList();
- _retryHelper.Retry(() =>
- {
- _fileSystem.Copy(backupPath, module, true);
- _fileSystem.Delete(backupPath);
- _backupList.TryRemove(module, out string _);
- }, retryStrategy, RetryAttempts);
+ if (documentSourceMap.Any(x => !x.documentExists))
+ return (false, documentSourceMap.FirstOrDefault(x => !x.documentExists).documentName);
- _retryHelper.Retry(() =>
- {
- if (_fileSystem.Exists(backupSymbolPath))
- {
- string symbolFile = Path.ChangeExtension(module, ".pdb");
- _fileSystem.Copy(backupSymbolPath, symbolFile, true);
- _fileSystem.Delete(backupSymbolPath);
- _backupList.TryRemove(symbolFile, out string _);
- }
- }, retryStrategy, RetryAttempts);
- }
+ return (true, string.Empty);
+ }
- public virtual void RestoreOriginalModules()
+ public void BackupOriginalModule(string module, string identifier)
+ {
+ string backupPath = GetBackupPath(module, identifier);
+ string backupSymbolPath = Path.ChangeExtension(backupPath, ".pdb");
+ _fileSystem.Copy(module, backupPath, true);
+ if (!_backupList.TryAdd(module, backupPath))
+ {
+ throw new ArgumentException($"Key already added '{module}'");
+ }
+
+ string symbolFile = Path.ChangeExtension(module, ".pdb");
+ if (_fileSystem.Exists(symbolFile))
+ {
+ _fileSystem.Copy(symbolFile, backupSymbolPath, true);
+ if (!_backupList.TryAdd(symbolFile, backupSymbolPath))
{
- // Restore the original module - retry up to 10 times, since the destination file could be locked
- // See: https://github.com/tonerdo/coverlet/issues/25
- Func retryStrategy = CreateRetryStrategy();
-
- foreach (string key in _backupList.Keys.ToList())
- {
- string backupPath = _backupList[key];
- _retryHelper.Retry(() =>
- {
- _fileSystem.Copy(backupPath, key, true);
- _fileSystem.Delete(backupPath);
- _backupList.TryRemove(key, out string _);
- }, retryStrategy, RetryAttempts);
- }
+ throw new ArgumentException($"Key already added '{module}'");
}
+ }
+ }
- public void DeleteHitsFile(string path)
+ public virtual void RestoreOriginalModule(string module, string identifier)
+ {
+ string backupPath = GetBackupPath(module, identifier);
+ string backupSymbolPath = Path.ChangeExtension(backupPath, ".pdb");
+
+ // Restore the original module - retry up to 10 times, since the destination file could be locked
+ // See: https://github.com/tonerdo/coverlet/issues/25
+ Func retryStrategy = CreateRetryStrategy();
+
+ _retryHelper.Retry(() =>
+ {
+ _fileSystem.Copy(backupPath, module, true);
+ _fileSystem.Delete(backupPath);
+ _backupList.TryRemove(module, out string _);
+ }, retryStrategy, RetryAttempts);
+
+ _retryHelper.Retry(() =>
+ {
+ if (_fileSystem.Exists(backupSymbolPath))
{
- Func retryStrategy = CreateRetryStrategy();
- _retryHelper.Retry(() => _fileSystem.Delete(path), retryStrategy, RetryAttempts);
+ string symbolFile = Path.ChangeExtension(module, ".pdb");
+ _fileSystem.Copy(backupSymbolPath, symbolFile, true);
+ _fileSystem.Delete(backupSymbolPath);
+ _backupList.TryRemove(symbolFile, out string _);
}
+ }, retryStrategy, RetryAttempts);
+ }
- public bool IsValidFilterExpression(string filter)
+ public virtual void RestoreOriginalModules()
+ {
+ // Restore the original module - retry up to 10 times, since the destination file could be locked
+ // See: https://github.com/tonerdo/coverlet/issues/25
+ Func retryStrategy = CreateRetryStrategy();
+
+ foreach (string key in _backupList.Keys.ToList())
+ {
+ string backupPath = _backupList[key];
+ _retryHelper.Retry(() =>
{
- if (filter == null)
- return false;
-
- if (!filter.StartsWith("["))
- return false;
+ _fileSystem.Copy(backupPath, key, true);
+ _fileSystem.Delete(backupPath);
+ _backupList.TryRemove(key, out string _);
+ }, retryStrategy, RetryAttempts);
+ }
+ }
- if (!filter.Contains("]"))
- return false;
+ public void DeleteHitsFile(string path)
+ {
+ Func retryStrategy = CreateRetryStrategy();
+ _retryHelper.Retry(() => _fileSystem.Delete(path), retryStrategy, RetryAttempts);
+ }
- if (filter.Count(f => f == '[') > 1)
- return false;
+ public bool IsValidFilterExpression(string filter)
+ {
+ if (filter == null)
+ return false;
- if (filter.Count(f => f == ']') > 1)
- return false;
+ if (!filter.StartsWith("["))
+ return false;
- if (filter.IndexOf(']') < filter.IndexOf('['))
- return false;
+ if (!filter.Contains("]"))
+ return false;
- if (filter.IndexOf(']') - filter.IndexOf('[') == 1)
- return false;
+ if (filter.Count(f => f == '[') > 1)
+ return false;
- if (filter.EndsWith("]"))
- return false;
+ if (filter.Count(f => f == ']') > 1)
+ return false;
- if (new Regex(@"[^\w*]").IsMatch(filter.Replace(".", "").Replace("?", "").Replace("[", "").Replace("]", "")))
- return false;
+ if (filter.IndexOf(']') < filter.IndexOf('['))
+ return false;
- return true;
- }
+ if (filter.IndexOf(']') - filter.IndexOf('[') == 1)
+ return false;
- public bool IsModuleExcluded(string module, string[] excludeFilters)
- {
- if (excludeFilters == null || excludeFilters.Length == 0)
- return false;
+ if (filter.EndsWith("]"))
+ return false;
- module = Path.GetFileNameWithoutExtension(module);
- if (module == null)
- return false;
+ if (new Regex(@"[^\w*]").IsMatch(filter.Replace(".", "").Replace("?", "").Replace("[", "").Replace("]", "")))
+ return false;
- foreach (string filter in excludeFilters)
- {
- string typePattern = filter.Substring(filter.IndexOf(']') + 1);
+ return true;
+ }
- if (typePattern != "*")
- continue;
+ public bool IsModuleExcluded(string module, string[] excludeFilters)
+ {
+ if (excludeFilters == null || excludeFilters.Length == 0)
+ return false;
- string modulePattern = filter.Substring(1, filter.IndexOf(']') - 1);
- modulePattern = WildcardToRegex(modulePattern);
+ module = Path.GetFileNameWithoutExtension(module);
+ if (module == null)
+ return false;
- var regex = new Regex(modulePattern);
+ foreach (string filter in excludeFilters)
+ {
+ string typePattern = filter.Substring(filter.IndexOf(']') + 1);
- if (regex.IsMatch(module))
- return true;
- }
+ if (typePattern != "*")
+ continue;
- return false;
- }
+ string modulePattern = filter.Substring(1, filter.IndexOf(']') - 1);
+ modulePattern = WildcardToRegex(modulePattern);
- public bool IsModuleIncluded(string module, string[] includeFilters)
- {
- if (includeFilters == null || includeFilters.Length == 0)
- return true;
+ var regex = new Regex(modulePattern);
- module = Path.GetFileNameWithoutExtension(module);
- if (module == null)
- return false;
+ if (regex.IsMatch(module))
+ return true;
+ }
- foreach (string filter in includeFilters)
- {
- string modulePattern = filter.Substring(1, filter.IndexOf(']') - 1);
+ return false;
+ }
- if (modulePattern == "*")
- return true;
+ public bool IsModuleIncluded(string module, string[] includeFilters)
+ {
+ if (includeFilters == null || includeFilters.Length == 0)
+ return true;
- modulePattern = WildcardToRegex(modulePattern);
+ module = Path.GetFileNameWithoutExtension(module);
+ if (module == null)
+ return false;
- var regex = new Regex(modulePattern);
+ foreach (string filter in includeFilters)
+ {
+ string modulePattern = filter.Substring(1, filter.IndexOf(']') - 1);
- if (regex.IsMatch(module))
- return true;
- }
+ if (modulePattern == "*")
+ return true;
- return false;
- }
+ modulePattern = WildcardToRegex(modulePattern);
- public bool IsTypeExcluded(string module, string type, string[] excludeFilters)
- {
- if (excludeFilters == null || excludeFilters.Length == 0)
- return false;
+ var regex = new Regex(modulePattern);
- module = Path.GetFileNameWithoutExtension(module);
- if (module == null)
- return false;
+ if (regex.IsMatch(module))
+ return true;
+ }
- return IsTypeFilterMatch(module, type, excludeFilters);
- }
+ return false;
+ }
- public bool IsTypeIncluded(string module, string type, string[] includeFilters)
- {
- if (includeFilters == null || includeFilters.Length == 0)
- return true;
+ public bool IsTypeExcluded(string module, string type, string[] excludeFilters)
+ {
+ if (excludeFilters == null || excludeFilters.Length == 0)
+ return false;
- module = Path.GetFileNameWithoutExtension(module);
- if (module == null)
- return true;
+ module = Path.GetFileNameWithoutExtension(module);
+ if (module == null)
+ return false;
- return IsTypeFilterMatch(module, type, includeFilters);
- }
+ return IsTypeFilterMatch(module, type, excludeFilters);
+ }
- public bool IsLocalMethod(string method)
- => new Regex(WildcardToRegex("<*>*__*|*")).IsMatch(method);
+ public bool IsTypeIncluded(string module, string type, string[] includeFilters)
+ {
+ if (includeFilters == null || includeFilters.Length == 0)
+ return true;
- public void SetLogger(ILogger logger)
- {
- _logger = logger;
- }
+ module = Path.GetFileNameWithoutExtension(module);
+ if (module == null)
+ return true;
- private static bool IsTypeFilterMatch(string module, string type, string[] filters)
- {
- Debug.Assert(module != null);
- Debug.Assert(filters != null);
+ return IsTypeFilterMatch(module, type, includeFilters);
+ }
- foreach (string filter in filters)
- {
- string typePattern = filter.Substring(filter.IndexOf(']') + 1);
- string modulePattern = filter.Substring(1, filter.IndexOf(']') - 1);
+ public bool IsLocalMethod(string method)
+ => new Regex(WildcardToRegex("<*>*__*|*")).IsMatch(method);
- typePattern = WildcardToRegex(typePattern);
- modulePattern = WildcardToRegex(modulePattern);
+ public void SetLogger(ILogger logger)
+ {
+ _logger = logger;
+ }
- if (new Regex(typePattern).IsMatch(type) && new Regex(modulePattern).IsMatch(module))
- return true;
- }
+ private static bool IsTypeFilterMatch(string module, string type, string[] filters)
+ {
+ Debug.Assert(module != null);
+ Debug.Assert(filters != null);
- return false;
- }
+ foreach (string filter in filters)
+ {
+ string typePattern = filter.Substring(filter.IndexOf(']') + 1);
+ string modulePattern = filter.Substring(1, filter.IndexOf(']') - 1);
- private static string GetBackupPath(string module, string identifier)
- {
- return Path.Combine(
- Path.GetTempPath(),
- Path.GetFileNameWithoutExtension(module) + "_" + identifier + ".dll"
- );
- }
+ typePattern = WildcardToRegex(typePattern);
+ modulePattern = WildcardToRegex(modulePattern);
- private Func CreateRetryStrategy(int initialSleepSeconds = 6)
- {
- TimeSpan retryStrategy()
- {
- var sleep = TimeSpan.FromMilliseconds(initialSleepSeconds);
- initialSleepSeconds *= 2;
- return sleep;
- }
+ if (new Regex(typePattern).IsMatch(type) && new Regex(modulePattern).IsMatch(module))
+ return true;
+ }
- return retryStrategy;
- }
+ return false;
+ }
- private static string WildcardToRegex(string pattern)
- {
- return "^" + Regex.Escape(pattern).
- Replace("\\*", ".*").
- Replace("\\?", "?") + "$";
- }
+ private static string GetBackupPath(string module, string identifier)
+ {
+ return Path.Combine(
+ Path.GetTempPath(),
+ Path.GetFileNameWithoutExtension(module) + "_" + identifier + ".dll"
+ );
+ }
- private static bool IsAssembly(string filePath)
- {
- Debug.Assert(filePath != null);
+ private Func CreateRetryStrategy(int initialSleepSeconds = 6)
+ {
+ TimeSpan retryStrategy()
+ {
+ var sleep = TimeSpan.FromMilliseconds(initialSleepSeconds);
+ initialSleepSeconds *= 2;
+ return sleep;
+ }
+
+ return retryStrategy;
+ }
- if (!(filePath.EndsWith(".exe") || filePath.EndsWith(".dll")))
- return false;
+ private static string WildcardToRegex(string pattern)
+ {
+ return "^" + Regex.Escape(pattern).
+ Replace("\\*", ".*").
+ Replace("\\?", "?") + "$";
+ }
- try
- {
- AssemblyName.GetAssemblyName(filePath);
- return true;
- }
- catch
- {
- return false;
- }
- }
+ private static bool IsAssembly(string filePath)
+ {
+ Debug.Assert(filePath != null);
+
+ if (!(filePath.EndsWith(".exe") || filePath.EndsWith(".dll")))
+ return false;
+
+ try
+ {
+ AssemblyName.GetAssemblyName(filePath);
+ return true;
+ }
+ catch
+ {
+ return false;
+ }
}
+ }
}
diff --git a/src/coverlet.core/Helpers/ProcessExitHandler.cs b/src/coverlet.core/Helpers/ProcessExitHandler.cs
index 1e570f07f..e941405d3 100644
--- a/src/coverlet.core/Helpers/ProcessExitHandler.cs
+++ b/src/coverlet.core/Helpers/ProcessExitHandler.cs
@@ -6,11 +6,11 @@
namespace Coverlet.Core.Helpers
{
- internal class ProcessExitHandler : IProcessExitHandler
+ internal class ProcessExitHandler : IProcessExitHandler
+ {
+ public void Add(EventHandler handler)
{
- public void Add(EventHandler handler)
- {
- AppDomain.CurrentDomain.ProcessExit += handler;
- }
+ AppDomain.CurrentDomain.ProcessExit += handler;
}
+ }
}
diff --git a/src/coverlet.core/Helpers/RetryHelper.cs b/src/coverlet.core/Helpers/RetryHelper.cs
index dcf3fa9d0..f28361dac 100644
--- a/src/coverlet.core/Helpers/RetryHelper.cs
+++ b/src/coverlet.core/Helpers/RetryHelper.cs
@@ -8,58 +8,58 @@
namespace Coverlet.Core.Helpers
{
- // A slightly amended version of the code found here: https://stackoverflow.com/a/1563234/186184
- // This code allows for varying backoff strategies through the use of Func.
- internal class RetryHelper : IRetryHelper
+ // A slightly amended version of the code found here: https://stackoverflow.com/a/1563234/186184
+ // This code allows for varying backoff strategies through the use of Func.
+ internal class RetryHelper : IRetryHelper
+ {
+ ///
+ /// Retry a void method.
+ ///
+ /// The action to perform
+ /// A function returning a Timespan defining the backoff strategy to use.
+ /// The maximum number of retries before bailing out. Defaults to 3.
+ public void Retry(
+ Action action,
+ Func backoffStrategy,
+ int maxAttemptCount = 3)
{
- ///
- /// Retry a void method.
- ///
- /// The action to perform
- /// A function returning a Timespan defining the backoff strategy to use.
- /// The maximum number of retries before bailing out. Defaults to 3.
- public void Retry(
- Action action,
- Func backoffStrategy,
- int maxAttemptCount = 3)
+ Do