diff --git a/src/coverlet.collector/DataCollection/CoverageManager.cs b/src/coverlet.collector/DataCollection/CoverageManager.cs index d34a89133..41801ff1f 100644 --- a/src/coverlet.collector/DataCollection/CoverageManager.cs +++ b/src/coverlet.collector/DataCollection/CoverageManager.cs @@ -23,7 +23,7 @@ internal class CoverageManager public IReporter[] Reporters { get; } public CoverageManager(CoverletSettings settings, TestPlatformEqtTrace eqtTrace, TestPlatformLogger logger, ICoverageWrapper coverageWrapper, - IInstrumentationHelper instrumentationHelper, IFileSystem fileSystem, ISourceRootTranslator sourceRootTranslator) + IInstrumentationHelper instrumentationHelper, IFileSystem fileSystem, ISourceRootTranslator sourceRootTranslator, ICecilSymbolHelper cecilSymbolHelper) : this(settings, settings.ReportFormats.Select(format => { @@ -39,19 +39,19 @@ public CoverageManager(CoverletSettings settings, TestPlatformEqtTrace eqtTrace, } }).Where(r => r != null).ToArray(), new CoverletLogger(eqtTrace, logger), - coverageWrapper, instrumentationHelper, fileSystem, sourceRootTranslator) + coverageWrapper, instrumentationHelper, fileSystem, sourceRootTranslator, cecilSymbolHelper) { } public CoverageManager(CoverletSettings settings, IReporter[] reporters, ILogger logger, ICoverageWrapper coverageWrapper, - IInstrumentationHelper instrumentationHelper, IFileSystem fileSystem, ISourceRootTranslator sourceRootTranslator) + IInstrumentationHelper instrumentationHelper, IFileSystem fileSystem, ISourceRootTranslator sourceRootTranslator, ICecilSymbolHelper cecilSymbolHelper) { // Store input vars Reporters = reporters; _coverageWrapper = coverageWrapper; // Coverage object - _coverage = _coverageWrapper.CreateCoverage(settings, logger, instrumentationHelper, fileSystem, sourceRootTranslator); + _coverage = _coverageWrapper.CreateCoverage(settings, logger, instrumentationHelper, fileSystem, sourceRootTranslator, cecilSymbolHelper); } /// diff --git a/src/coverlet.collector/DataCollection/CoverageWrapper.cs b/src/coverlet.collector/DataCollection/CoverageWrapper.cs index 91f504c07..2beef2707 100644 --- a/src/coverlet.collector/DataCollection/CoverageWrapper.cs +++ b/src/coverlet.collector/DataCollection/CoverageWrapper.cs @@ -15,7 +15,7 @@ internal class CoverageWrapper : ICoverageWrapper /// Coverlet settings /// Coverlet logger /// Coverage object - public Coverage CreateCoverage(CoverletSettings settings, ILogger coverletLogger, IInstrumentationHelper instrumentationHelper, IFileSystem fileSystem, ISourceRootTranslator sourceRootTranslator) + public Coverage CreateCoverage(CoverletSettings settings, ILogger coverletLogger, IInstrumentationHelper instrumentationHelper, IFileSystem fileSystem, ISourceRootTranslator sourceRootTranslator, ICecilSymbolHelper cecilSymbolHelper) { return new Coverage( settings.TestModule, @@ -31,7 +31,8 @@ public Coverage CreateCoverage(CoverletSettings settings, ILogger coverletLogger coverletLogger, instrumentationHelper, fileSystem, - sourceRootTranslator); + sourceRootTranslator, + cecilSymbolHelper); } /// diff --git a/src/coverlet.collector/DataCollection/CoverletCoverageCollector.cs b/src/coverlet.collector/DataCollection/CoverletCoverageCollector.cs index ddd73b0d8..d5094dc91 100644 --- a/src/coverlet.collector/DataCollection/CoverletCoverageCollector.cs +++ b/src/coverlet.collector/DataCollection/CoverletCoverageCollector.cs @@ -7,6 +7,7 @@ using Coverlet.Collector.Utilities.Interfaces; using Coverlet.Core.Abstractions; using Coverlet.Core.Helpers; +using Coverlet.Core.Symbols; using Microsoft.Extensions.DependencyInjection; using Microsoft.VisualStudio.TestPlatform.ObjectModel.DataCollection; @@ -133,7 +134,7 @@ private void OnSessionStart(object sender, SessionStartEventArgs sessionStartEve // Get coverage and attachment managers _coverageManager = new CoverageManager(coverletSettings, _eqtTrace, _logger, _coverageWrapper, _serviceProvider.GetRequiredService(), _serviceProvider.GetRequiredService(), - _serviceProvider.GetRequiredService()); + _serviceProvider.GetRequiredService(), _serviceProvider.GetRequiredService()); // Instrument modules _coverageManager.InstrumentModules(); @@ -227,6 +228,7 @@ private static IServiceCollection GetDefaultServiceCollection(TestPlatformEqtTra serviceCollection.AddSingleton(); // We cache resolutions serviceCollection.AddSingleton(serviceProvider => new SourceRootTranslator(testModule, serviceProvider.GetRequiredService(), serviceProvider.GetRequiredService())); + serviceCollection.AddSingleton(); return serviceCollection; } } diff --git a/src/coverlet.collector/Utilities/Interfaces/ICoverageWrapper.cs b/src/coverlet.collector/Utilities/Interfaces/ICoverageWrapper.cs index 59c6c232d..1358fab1b 100644 --- a/src/coverlet.collector/Utilities/Interfaces/ICoverageWrapper.cs +++ b/src/coverlet.collector/Utilities/Interfaces/ICoverageWrapper.cs @@ -14,12 +14,13 @@ internal interface ICoverageWrapper /// Creates a coverage object from given coverlet settings /// /// Coverlet settings - /// Coverlet logger + /// Coverlet logger /// Coverlet instrumentationHelper /// Coverlet fileSystem /// Coverlet sourceRootTranslator + /// /// Coverage object - Coverage CreateCoverage(CoverletSettings settings, ILogger logger, IInstrumentationHelper instrumentationHelper, IFileSystem fileSystem, ISourceRootTranslator sourceRootTranslator); + Coverage CreateCoverage(CoverletSettings settings, ILogger logger, IInstrumentationHelper instrumentationHelper, IFileSystem fileSystem, ISourceRootTranslator sourceRootTranslator, ICecilSymbolHelper cecilSymbolHelper); /// /// Gets the coverage result from provided coverage object diff --git a/src/coverlet.console/Program.cs b/src/coverlet.console/Program.cs index c3b3d4fe0..2493857ef 100644 --- a/src/coverlet.console/Program.cs +++ b/src/coverlet.console/Program.cs @@ -12,6 +12,7 @@ using Coverlet.Core.Enums; using Coverlet.Core.Helpers; using Coverlet.Core.Reporters; +using Coverlet.Core.Symbols; using McMaster.Extensions.CommandLineUtils; using Microsoft.Extensions.DependencyInjection; @@ -29,12 +30,12 @@ static int Main(string[] args) // 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(); var fileSystem = serviceProvider.GetService(); - var sourceTranslator = serviceProvider.GetService(); var app = new CommandLineApplication(); app.Name = "coverlet"; @@ -86,9 +87,10 @@ static int Main(string[] args) mergeWith.Value(), useSourceLink.HasValue(), logger, - serviceProvider.GetService(), + serviceProvider.GetRequiredService(), fileSystem, - sourceTranslator); + serviceProvider.GetRequiredService(), + serviceProvider.GetRequiredService()); coverage.PrepareModules(); Process process = new Process(); diff --git a/src/coverlet.core/Abstractions/ICecilSymbolHelper.cs b/src/coverlet.core/Abstractions/ICecilSymbolHelper.cs new file mode 100644 index 000000000..222a34803 --- /dev/null +++ b/src/coverlet.core/Abstractions/ICecilSymbolHelper.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using Coverlet.Core.Symbols; +using Mono.Cecil; +using Mono.Cecil.Cil; + +namespace Coverlet.Core.Abstractions +{ + internal interface ICecilSymbolHelper + { + IReadOnlyList GetBranchPoints(MethodDefinition methodDefinition); + bool SkipNotCoverableInstruction(MethodDefinition methodDefinition, Instruction instruction); + } +} diff --git a/src/coverlet.core/Coverage.cs b/src/coverlet.core/Coverage.cs index 11c89113c..f3d83aaf9 100644 --- a/src/coverlet.core/Coverage.cs +++ b/src/coverlet.core/Coverage.cs @@ -27,6 +27,7 @@ internal class Coverage private IInstrumentationHelper _instrumentationHelper; private IFileSystem _fileSystem; private ISourceRootTranslator _sourceRootTranslator; + private ICecilSymbolHelper _cecilSymbolHelper; private List _results; public string Identifier @@ -47,7 +48,8 @@ public Coverage(string module, ILogger logger, IInstrumentationHelper instrumentationHelper, IFileSystem fileSystem, - ISourceRootTranslator sourceRootTranslator) + ISourceRootTranslator sourceRootTranslator, + ICecilSymbolHelper cecilSymbolHelper) { _module = module; _includeFilters = includeFilters; @@ -63,6 +65,7 @@ public Coverage(string module, _instrumentationHelper = instrumentationHelper; _fileSystem = fileSystem; _sourceRootTranslator = sourceRootTranslator; + _cecilSymbolHelper = cecilSymbolHelper; _identifier = Guid.NewGuid().ToString(); _results = new List(); @@ -100,7 +103,7 @@ public CoveragePrepareResult PrepareModules() continue; } - var instrumenter = new Instrumenter(module, _identifier, _excludeFilters, _includeFilters, _excludedSourceFiles, _excludeAttributes, _singleHit, _logger, _instrumentationHelper, _fileSystem, _sourceRootTranslator); + var instrumenter = new Instrumenter(module, _identifier, _excludeFilters, _includeFilters, _excludedSourceFiles, _excludeAttributes, _singleHit, _logger, _instrumentationHelper, _fileSystem, _sourceRootTranslator, _cecilSymbolHelper); if (instrumenter.CanInstrument()) { diff --git a/src/coverlet.core/Instrumentation/Instrumenter.cs b/src/coverlet.core/Instrumentation/Instrumenter.cs index 86e32bca2..b26af5f1e 100644 --- a/src/coverlet.core/Instrumentation/Instrumenter.cs +++ b/src/coverlet.core/Instrumentation/Instrumenter.cs @@ -30,6 +30,7 @@ internal class Instrumenter private readonly IInstrumentationHelper _instrumentationHelper; private readonly IFileSystem _fileSystem; private readonly ISourceRootTranslator _sourceRootTranslator; + private readonly ICecilSymbolHelper _cecilSymbolHelper; private InstrumenterResult _result; private FieldDefinition _customTrackerHitsArray; private FieldDefinition _customTrackerHitsFilePath; @@ -57,7 +58,8 @@ public Instrumenter( ILogger logger, IInstrumentationHelper instrumentationHelper, IFileSystem fileSystem, - ISourceRootTranslator sourceRootTranslator) + ISourceRootTranslator sourceRootTranslator, + ICecilSymbolHelper cecilSymbolHelper) { _module = module; _identifier = identifier; @@ -71,6 +73,7 @@ public Instrumenter( _instrumentationHelper = instrumentationHelper; _fileSystem = fileSystem; _sourceRootTranslator = sourceRootTranslator; + _cecilSymbolHelper = cecilSymbolHelper; } public bool CanInstrument() @@ -447,7 +450,7 @@ private void InstrumentIL(MethodDefinition method) var index = 0; var count = processor.Body.Instructions.Count; - var branchPoints = CecilSymbolHelper.GetBranchPoints(method); + var branchPoints = _cecilSymbolHelper.GetBranchPoints(method); for (int n = 0; n < count; n++) { @@ -456,7 +459,7 @@ private void InstrumentIL(MethodDefinition method) var targetedBranchPoints = branchPoints.Where(p => p.EndOffset == instruction.Offset); // Check if the instruction is coverable - if (CecilSymbolHelper.SkipNotCoverableInstruction(method, instruction)) + if (_cecilSymbolHelper.SkipNotCoverableInstruction(method, instruction)) { index++; continue; diff --git a/src/coverlet.core/Symbols/CecilSymbolHelper.cs b/src/coverlet.core/Symbols/CecilSymbolHelper.cs index 074d8153b..19069bfaf 100644 --- a/src/coverlet.core/Symbols/CecilSymbolHelper.cs +++ b/src/coverlet.core/Symbols/CecilSymbolHelper.cs @@ -7,7 +7,7 @@ using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; - +using Coverlet.Core.Abstractions; using Coverlet.Core.Extensions; using Mono.Cecil; @@ -16,16 +16,11 @@ namespace Coverlet.Core.Symbols { - internal static class CecilSymbolHelper + internal class CecilSymbolHelper : ICecilSymbolHelper { private const int StepOverLineCode = 0xFEEFEE; - private static ConcurrentDictionary CompilerGeneratedBranchesToExclude = null; - - static CecilSymbolHelper() - { - // Create single instance, we cannot collide because we use full method name as key - CompilerGeneratedBranchesToExclude = new ConcurrentDictionary(); - } + // Create single instance, we cannot collide because we use full method name as key + private readonly ConcurrentDictionary _compilerGeneratedBranchesToExclude = new ConcurrentDictionary(); // In case of nested compiler generated classes, only the root one presents the CompilerGenerated attribute. // So let's search up to the outermost declaring type to find the attribute @@ -265,9 +260,9 @@ private static bool SkipGeneratedBranchForExceptionRethrown(List in instructions[branchIndex + 3].OpCode == OpCodes.Throw; } - private static bool SkipGeneratedBranchesForExceptionHandlers(MethodDefinition methodDefinition, Instruction instruction, List bodyInstructions) + private bool SkipGeneratedBranchesForExceptionHandlers(MethodDefinition methodDefinition, Instruction instruction, List bodyInstructions) { - if (!CompilerGeneratedBranchesToExclude.ContainsKey(methodDefinition.FullName)) + if (!_compilerGeneratedBranchesToExclude.ContainsKey(methodDefinition.FullName)) { /* This method is used to parse compiler generated code inside async state machine and find branches generated for exception catch blocks @@ -393,13 +388,13 @@ private static bool SkipGeneratedBranchesForExceptionHandlers(MethodDefinition m } } - CompilerGeneratedBranchesToExclude.TryAdd(methodDefinition.FullName, detectedBranches.ToArray()); + _compilerGeneratedBranchesToExclude.TryAdd(methodDefinition.FullName, detectedBranches.ToArray()); } - return CompilerGeneratedBranchesToExclude[methodDefinition.FullName].Contains(instruction.Offset); + return _compilerGeneratedBranchesToExclude[methodDefinition.FullName].Contains(instruction.Offset); } - public static List GetBranchPoints(MethodDefinition methodDefinition) + public IReadOnlyList GetBranchPoints(MethodDefinition methodDefinition) { var list = new List(); if (methodDefinition is null) @@ -664,7 +659,7 @@ await ... IL_00eb: br.s IL_00ed ... */ - internal static bool SkipNotCoverableInstruction(MethodDefinition methodDefinition, Instruction instruction) + public bool SkipNotCoverableInstruction(MethodDefinition methodDefinition, Instruction instruction) { if (!IsMoveNextInsideAsyncStateMachine(methodDefinition)) { diff --git a/src/coverlet.msbuild.tasks/InstrumentationTask.cs b/src/coverlet.msbuild.tasks/InstrumentationTask.cs index d09f92371..1331bbbe8 100644 --- a/src/coverlet.msbuild.tasks/InstrumentationTask.cs +++ b/src/coverlet.msbuild.tasks/InstrumentationTask.cs @@ -5,6 +5,7 @@ using Coverlet.Core; using Coverlet.Core.Abstractions; using Coverlet.Core.Helpers; +using Coverlet.Core.Symbols; using Microsoft.Build.Framework; using Microsoft.Build.Utilities; using Microsoft.Extensions.DependencyInjection; @@ -131,6 +132,7 @@ public override bool Execute() serviceCollection.AddSingleton(serviceProvider => new SourceRootTranslator(_path, serviceProvider.GetRequiredService(), serviceProvider.GetRequiredService())); // We need to keep singleton/static semantics serviceCollection.AddSingleton(); + serviceCollection.AddSingleton(); ServiceProvider = serviceCollection.BuildServiceProvider(); @@ -156,7 +158,8 @@ public override bool Execute() _logger, ServiceProvider.GetService(), fileSystem, - ServiceProvider.GetService()); + ServiceProvider.GetService(), + ServiceProvider.GetService()); CoveragePrepareResult prepareResult = coverage.PrepareModules(); InstrumenterState = new TaskItem(System.IO.Path.GetTempFileName()); diff --git a/test/coverlet.collector.tests/CoverletCoverageDataCollectorTests.cs b/test/coverlet.collector.tests/CoverletCoverageDataCollectorTests.cs index 12c7bc937..3c174d4cc 100644 --- a/test/coverlet.collector.tests/CoverletCoverageDataCollectorTests.cs +++ b/test/coverlet.collector.tests/CoverletCoverageDataCollectorTests.cs @@ -15,6 +15,7 @@ using Coverlet.Core.Reporters; using Coverlet.Core.Abstractions; using Coverlet.Core.Helpers; +using Coverlet.Core.Symbols; using Microsoft.Extensions.DependencyInjection; namespace Coverlet.Collector.Tests @@ -61,6 +62,7 @@ public void OnSessionStartShouldInitializeCoverageWithCorrectCoverletSettings() serviceCollection.AddTransient(_ => new CoverletLogger(eqtTrace, logger)); serviceCollection.AddSingleton(); serviceCollection.AddSingleton(serviceProvider => new SourceRootTranslator(testModule, serviceProvider.GetRequiredService(), serviceProvider.GetRequiredService())); + serviceCollection.AddSingleton(); return serviceCollection; }; _coverletCoverageDataCollector = new CoverletCoverageCollector(new TestPlatformEqtTrace(), _mockCoverageWrapper.Object, _mockCountDownEventFactory.Object, serviceCollectionFactory); @@ -76,7 +78,7 @@ public void OnSessionStartShouldInitializeCoverageWithCorrectCoverletSettings() _mockDataColectionEvents.Raise(x => x.SessionStart += null, new SessionStartEventArgs(sessionStartProperties)); - _mockCoverageWrapper.Verify(x => x.CreateCoverage(It.Is(y => string.Equals(y.TestModule, "abc.dll")), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Once); + _mockCoverageWrapper.Verify(x => x.CreateCoverage(It.Is(y => string.Equals(y.TestModule, "abc.dll")), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Once); } [Fact] @@ -94,6 +96,7 @@ public void OnSessionStartShouldPrepareModulesForCoverage() serviceCollection.AddTransient(_ => new CoverletLogger(eqtTrace, logger)); serviceCollection.AddSingleton(); serviceCollection.AddSingleton(serviceProvider => new SourceRootTranslator(testModule, serviceProvider.GetRequiredService(), serviceProvider.GetRequiredService())); + serviceCollection.AddSingleton(); return serviceCollection; }; _coverletCoverageDataCollector = new CoverletCoverageCollector(new TestPlatformEqtTrace(), _mockCoverageWrapper.Object, _mockCountDownEventFactory.Object, serviceCollectionFactory); @@ -111,14 +114,14 @@ public void OnSessionStartShouldPrepareModulesForCoverage() new Mock().Object, new Mock().Object); - Coverage coverage = new Coverage("abc.dll", null, null, null, null, null, true, true, "abc.json", true, It.IsAny(), instrumentationHelper, new Mock().Object, new Mock().Object); + Coverage coverage = new Coverage("abc.dll", null, null, null, null, null, true, true, "abc.json", true, It.IsAny(), instrumentationHelper, new Mock().Object, new Mock().Object, new Mock().Object); sessionStartProperties.Add("TestSources", new List { "abc.dll" }); - _mockCoverageWrapper.Setup(x => x.CreateCoverage(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).Returns(coverage); + _mockCoverageWrapper.Setup(x => x.CreateCoverage(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).Returns(coverage); _mockDataColectionEvents.Raise(x => x.SessionStart += null, new SessionStartEventArgs(sessionStartProperties)); - _mockCoverageWrapper.Verify(x => x.CreateCoverage(It.Is(y => y.TestModule.Contains("abc.dll")), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Once); + _mockCoverageWrapper.Verify(x => x.CreateCoverage(It.Is(y => y.TestModule.Contains("abc.dll")), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Once); _mockCoverageWrapper.Verify(x => x.PrepareModules(It.IsAny()), Times.Once); } @@ -134,6 +137,7 @@ public void OnSessionEndShouldSendGetCoverageReportToTestPlatform() serviceCollection.AddTransient(_ => new CoverletLogger(eqtTrace, logger)); serviceCollection.AddSingleton(); serviceCollection.AddSingleton(serviceProvider => new SourceRootTranslator(testModule, serviceProvider.GetRequiredService(), serviceProvider.GetRequiredService())); + serviceCollection.AddSingleton(); return serviceCollection; }; _coverletCoverageDataCollector = new CoverletCoverageCollector(new TestPlatformEqtTrace(), new CoverageWrapper(), _mockCountDownEventFactory.Object, serviceCollectionFactory); @@ -181,6 +185,7 @@ public void OnSessionEndShouldSendCoverageReportsForMultipleFormatsToTestPlatfor serviceCollection.AddTransient(_ => new CoverletLogger(eqtTrace, logger)); serviceCollection.AddSingleton(); serviceCollection.AddSingleton(serviceProvider => new SourceRootTranslator(testModule, serviceProvider.GetRequiredService(), serviceProvider.GetRequiredService())); + serviceCollection.AddSingleton(); return serviceCollection; }; _coverletCoverageDataCollector = new CoverletCoverageCollector(new TestPlatformEqtTrace(), new CoverageWrapper(), _mockCountDownEventFactory.Object, serviceCollectionFactory); @@ -233,6 +238,7 @@ public void OnSessionStartShouldLogWarningIfInstrumentationFailed() serviceCollection.AddTransient(_ => new CoverletLogger(eqtTrace, logger)); serviceCollection.AddSingleton(); serviceCollection.AddSingleton(serviceProvider => new SourceRootTranslator(testModule, serviceProvider.GetRequiredService(), serviceProvider.GetRequiredService())); + serviceCollection.AddSingleton(); return serviceCollection; }; _coverletCoverageDataCollector = new CoverletCoverageCollector(new TestPlatformEqtTrace(), _mockCoverageWrapper.Object, _mockCountDownEventFactory.Object, serviceCollectionFactory); diff --git a/test/coverlet.core.tests/Coverage/CoverageTests.ExcludeFromCoverageAttribute.cs b/test/coverlet.core.tests/Coverage/CoverageTests.ExcludeFromCoverageAttribute.cs index 874abc514..b82461e1b 100644 --- a/test/coverlet.core.tests/Coverage/CoverageTests.ExcludeFromCoverageAttribute.cs +++ b/test/coverlet.core.tests/Coverage/CoverageTests.ExcludeFromCoverageAttribute.cs @@ -7,6 +7,7 @@ using Coverlet.Core.Abstractions; using Coverlet.Core.Helpers; using Coverlet.Core.Samples.Tests; +using Coverlet.Core.Symbols; using Coverlet.Tests.Xunit.Extensions; using Moq; using Xunit; @@ -35,7 +36,7 @@ public void TestCoverageSkipModule__AssemblyMarkedAsExcludeFromCodeCoverage() // test skip module include test assembly feature var coverage = new Coverage(excludedbyattributeDll, new string[] { "[coverlet.tests.projectsample.excludedbyattribute*]*" }, Array.Empty(), Array.Empty(), Array.Empty(), Array.Empty(), true, false, string.Empty, false, loggerMock.Object, instrumentationHelper, partialMockFileSystem.Object, - new SourceRootTranslator(loggerMock.Object, new FileSystem())); + new SourceRootTranslator(loggerMock.Object, new FileSystem()), new CecilSymbolHelper()); CoveragePrepareResult result = coverage.PrepareModules(); Assert.Empty(result.Results); loggerMock.Verify(l => l.LogVerbose(It.IsAny())); diff --git a/test/coverlet.core.tests/Coverage/CoverageTests.cs b/test/coverlet.core.tests/Coverage/CoverageTests.cs index 8ce3395f1..92f2b92d7 100644 --- a/test/coverlet.core.tests/Coverage/CoverageTests.cs +++ b/test/coverlet.core.tests/Coverage/CoverageTests.cs @@ -3,6 +3,7 @@ using Coverlet.Core.Abstractions; using Coverlet.Core.Helpers; +using Coverlet.Core.Symbols; using Moq; using Xunit; @@ -29,7 +30,7 @@ public void TestCoverage() new SourceRootTranslator(module, new Mock().Object, new FileSystem())); var coverage = new Coverage(Path.Combine(directory.FullName, Path.GetFileName(module)), Array.Empty(), Array.Empty(), Array.Empty(), Array.Empty(), - Array.Empty(), false, false, string.Empty, false, _mockLogger.Object, instrumentationHelper, new FileSystem(), new SourceRootTranslator(_mockLogger.Object, new FileSystem())); + Array.Empty(), false, false, string.Empty, false, _mockLogger.Object, instrumentationHelper, new FileSystem(), new SourceRootTranslator(_mockLogger.Object, new FileSystem()), new CecilSymbolHelper()); coverage.PrepareModules(); var result = coverage.GetCoverageResult(); @@ -56,7 +57,7 @@ public void TestCoverageWithTestAssembly() var coverage = new Coverage(Path.Combine(directory.FullName, Path.GetFileName(module)), Array.Empty(), Array.Empty(), Array.Empty(), Array.Empty(), Array.Empty(), true, false, string.Empty, false, _mockLogger.Object, instrumentationHelper, new FileSystem(), - new SourceRootTranslator(module, _mockLogger.Object, new FileSystem())); + new SourceRootTranslator(module, _mockLogger.Object, new FileSystem()), new CecilSymbolHelper()); coverage.PrepareModules(); var result = coverage.GetCoverageResult(); diff --git a/test/coverlet.core.tests/Coverage/InstrumenterHelper.cs b/test/coverlet.core.tests/Coverage/InstrumenterHelper.cs index fb7a63c28..23fe39718 100644 --- a/test/coverlet.core.tests/Coverage/InstrumenterHelper.cs +++ b/test/coverlet.core.tests/Coverage/InstrumenterHelper.cs @@ -6,10 +6,10 @@ using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; - using Coverlet.Core.Abstractions; using Coverlet.Core.Helpers; using Coverlet.Core.Reporters; +using Coverlet.Core.Symbols; using Microsoft.Extensions.DependencyInjection; using Moq; using Palmmedia.ReportGenerator.Core; @@ -99,7 +99,7 @@ async public static Task Run(Func callM "[xunit.*]*", "[coverlet.*]*" }).ToArray(), Array.Empty(), Array.Empty(), true, false, "", false, new Logger(logFile), - _processWideContainer.GetService(), _processWideContainer.GetService(), _processWideContainer.GetService()); + _processWideContainer.GetService(), _processWideContainer.GetService(), _processWideContainer.GetService(), _processWideContainer.GetService()); CoveragePrepareResult prepareResult = coverage.PrepareModules(); Assert.Single(prepareResult.Results); @@ -153,6 +153,8 @@ private static void SetTestContainer(string testModule = null, bool disableResto new SourceRootTranslator(serviceProvider.GetRequiredService(), serviceProvider.GetRequiredService()) : new SourceRootTranslator(testModule, serviceProvider.GetRequiredService(), serviceProvider.GetRequiredService())); + serviceCollection.AddSingleton(); + return serviceCollection.BuildServiceProvider(); }); } diff --git a/test/coverlet.core.tests/Instrumentation/InstrumenterTests.cs b/test/coverlet.core.tests/Instrumentation/InstrumenterTests.cs index 79d958e77..e362b1563 100644 --- a/test/coverlet.core.tests/Instrumentation/InstrumenterTests.cs +++ b/test/coverlet.core.tests/Instrumentation/InstrumenterTests.cs @@ -8,6 +8,7 @@ using Coverlet.Core.Helpers; using Coverlet.Core.Abstractions; using Coverlet.Core.Samples.Tests; +using Coverlet.Core.Symbols; using Coverlet.Tests.Xunit.Extensions; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; @@ -75,7 +76,7 @@ public void TestCoreLibInstrumentation() InstrumentationHelper instrumentationHelper = new InstrumentationHelper(new ProcessExitHandler(), new RetryHelper(), partialMockFileSystem.Object, _mockLogger.Object, sourceRootTranslator); Instrumenter instrumenter = new Instrumenter(Path.Combine(directory.FullName, files[0]), "_coverlet_instrumented", Array.Empty(), Array.Empty(), Array.Empty(), - Array.Empty(), false, _mockLogger.Object, instrumentationHelper, partialMockFileSystem.Object, sourceRootTranslator); + Array.Empty(), false, _mockLogger.Object, instrumentationHelper, partialMockFileSystem.Object, sourceRootTranslator, new CecilSymbolHelper()); Assert.True(instrumenter.CanInstrument()); InstrumenterResult result = instrumenter.Instrument(); @@ -222,7 +223,7 @@ private InstrumenterTest CreateInstrumentor(bool fakeCoreLibModule = false, stri module = Path.Combine(directory.FullName, destModule); Instrumenter instrumenter = new Instrumenter(module, identifier, Array.Empty(), Array.Empty(), Array.Empty(), attributesToIgnore, false, - _mockLogger.Object, instrumentationHelper, new FileSystem(), new SourceRootTranslator(_mockLogger.Object, new FileSystem())); + _mockLogger.Object, instrumentationHelper, new FileSystem(), new SourceRootTranslator(_mockLogger.Object, new FileSystem()), new CecilSymbolHelper()); return new InstrumenterTest { Instrumenter = instrumenter, @@ -399,7 +400,7 @@ public void SkipEmbeddedPpdbWithoutLocalSource() new SourceRootTranslator(xunitDll, new Mock().Object, new FileSystem())); Instrumenter instrumenter = new Instrumenter(xunitDll, "_xunit_instrumented", Array.Empty(), Array.Empty(), Array.Empty(), - Array.Empty(), false, loggerMock.Object, instrumentationHelper, new FileSystem(), new SourceRootTranslator(xunitDll, loggerMock.Object, new FileSystem())); + Array.Empty(), false, loggerMock.Object, instrumentationHelper, new FileSystem(), new SourceRootTranslator(xunitDll, loggerMock.Object, new FileSystem()), new CecilSymbolHelper()); Assert.True(instrumentationHelper.HasPdb(xunitDll, out bool embedded)); Assert.True(embedded); Assert.False(instrumenter.CanInstrument()); @@ -412,7 +413,7 @@ public void SkipEmbeddedPpdbWithoutLocalSource() new SourceRootTranslator(sample, new Mock().Object, new FileSystem())); instrumenter = new Instrumenter(sample, "_coverlet_tests_projectsample_empty", Array.Empty(), Array.Empty(), Array.Empty(), - Array.Empty(), false, loggerMock.Object, instrumentationHelper, new FileSystem(), new SourceRootTranslator(sample, loggerMock.Object, new FileSystem())); + Array.Empty(), false, loggerMock.Object, instrumentationHelper, new FileSystem(), new SourceRootTranslator(sample, loggerMock.Object, new FileSystem()), new CecilSymbolHelper()); Assert.True(instrumentationHelper.HasPdb(sample, out embedded)); Assert.False(embedded); @@ -458,7 +459,7 @@ public void SkipPpdbWithoutLocalSource() string sample = Directory.GetFiles(Path.Combine(Directory.GetCurrentDirectory(), "TestAssets"), dllFileName).First(); var loggerMock = new Mock(); Instrumenter instrumenter = new Instrumenter(sample, "_75d9f96508d74def860a568f426ea4a4_instrumented", Array.Empty(), Array.Empty(), Array.Empty(), - Array.Empty(), false, loggerMock.Object, instrumentationHelper, partialMockFileSystem.Object, new SourceRootTranslator(loggerMock.Object, new FileSystem())); + Array.Empty(), false, loggerMock.Object, instrumentationHelper, partialMockFileSystem.Object, new SourceRootTranslator(loggerMock.Object, new FileSystem()), new CecilSymbolHelper()); Assert.True(instrumentationHelper.HasPdb(sample, out bool embedded)); Assert.False(embedded); Assert.False(instrumenter.CanInstrument()); @@ -475,7 +476,7 @@ public void TestInstrument_MissingModule() new SourceRootTranslator(new Mock().Object, new FileSystem())); var instrumenter = new Instrumenter("test", "_test_instrumented", Array.Empty(), Array.Empty(), Array.Empty(), - Array.Empty(), false, loggerMock.Object, instrumentationHelper, new FileSystem(), new SourceRootTranslator(loggerMock.Object, new FileSystem())); + Array.Empty(), false, loggerMock.Object, instrumentationHelper, new FileSystem(), new SourceRootTranslator(loggerMock.Object, new FileSystem()), new CecilSymbolHelper()); Assert.False(instrumenter.CanInstrument()); loggerMock.Verify(l => l.LogWarning(It.IsAny())); } @@ -498,7 +499,7 @@ public void TestInstrument_AssemblyMarkedAsExcludeFromCodeCoverage() new SourceRootTranslator(new Mock().Object, new FileSystem())); Instrumenter instrumenter = new Instrumenter(excludedbyattributeDll, "_xunit_excludedbyattribute", Array.Empty(), Array.Empty(), Array.Empty(), - Array.Empty(), false, loggerMock.Object, instrumentationHelper, partialMockFileSystem.Object, new SourceRootTranslator(loggerMock.Object, new FileSystem())); + Array.Empty(), false, loggerMock.Object, instrumentationHelper, partialMockFileSystem.Object, new SourceRootTranslator(loggerMock.Object, new FileSystem()), new CecilSymbolHelper()); InstrumenterResult result = instrumenter.Instrument(); Assert.Empty(result.Documents); loggerMock.Verify(l => l.LogVerbose(It.IsAny())); diff --git a/test/coverlet.core.tests/Symbols/CecilSymbolHelperTests.cs b/test/coverlet.core.tests/Symbols/CecilSymbolHelperTests.cs index e91f19c77..19964828c 100644 --- a/test/coverlet.core.tests/Symbols/CecilSymbolHelperTests.cs +++ b/test/coverlet.core.tests/Symbols/CecilSymbolHelperTests.cs @@ -1,11 +1,9 @@ -using System; using System.IO; using System.Linq; using System.Reflection; using Xunit; using Coverlet.Core.Samples.Tests; - using Mono.Cecil; using Mono.Cecil.Cil; @@ -13,7 +11,9 @@ namespace Coverlet.Core.Symbols.Tests { public class CecilSymbolHelperTests { - private ModuleDefinition _module; + private readonly ModuleDefinition _module; + private readonly CecilSymbolHelper _cecilSymbolHelper; + public CecilSymbolHelperTests() { var location = GetType().Assembly.Location; @@ -21,6 +21,7 @@ public CecilSymbolHelperTests() resolver.AddSearchDirectory(Path.GetDirectoryName(location)); var parameters = new ReaderParameters { ReadSymbols = true, AssemblyResolver = resolver }; _module = ModuleDefinition.ReadModule(location, parameters); + _cecilSymbolHelper = new CecilSymbolHelper(); } [Fact] @@ -31,7 +32,7 @@ public void GetBranchPoints_OneBranch() var method = type.Methods.First(x => x.FullName.Contains($"::{nameof(DeclaredConstructorClass.HasSingleDecision)}")); // act - var points = CecilSymbolHelper.GetBranchPoints(method); + var points = _cecilSymbolHelper.GetBranchPoints(method); // assert Assert.NotNull(points); @@ -53,7 +54,7 @@ public void GetBranchPoints_Using_Where_GeneratedBranchesIgnored() var method = type.Methods.First(x => x.FullName.Contains($"::{nameof(DeclaredConstructorClass.HasSimpleUsingStatement)}")); // act - var points = CecilSymbolHelper.GetBranchPoints(method); + var points = _cecilSymbolHelper.GetBranchPoints(method); Assert.Equal(2, points.Count()); } @@ -66,7 +67,7 @@ public void GetBranchPoints_GeneratedBranches_DueToCachedAnonymousMethodDelegate var method = type.Methods.First(x => x.FullName.Contains($"::{nameof(DeclaredConstructorClass.HasSimpleTaskWithLambda)}")); // act - var points = CecilSymbolHelper.GetBranchPoints(method); + var points = _cecilSymbolHelper.GetBranchPoints(method); Assert.Empty(points); } @@ -79,7 +80,7 @@ public void GetBranchPoints_TwoBranch() var method = type.Methods.First(x => x.FullName.Contains($"::{nameof(DeclaredConstructorClass.HasTwoDecisions)}")); // act - var points = CecilSymbolHelper.GetBranchPoints(method); + var points = _cecilSymbolHelper.GetBranchPoints(method); // assert Assert.NotNull(points); @@ -98,7 +99,7 @@ public void GetBranchPoints_CompleteIf() var method = type.Methods.First(x => x.FullName.Contains($"::{nameof(DeclaredConstructorClass.HasCompleteIf)}")); // act - var points = CecilSymbolHelper.GetBranchPoints(method); + var points = _cecilSymbolHelper.GetBranchPoints(method); // assert Assert.NotNull(points); @@ -117,7 +118,7 @@ public void GetBranchPoints_Switch() var method = type.Methods.First(x => x.FullName.Contains($"::{nameof(DeclaredConstructorClass.HasSwitch)}")); // act - var points = CecilSymbolHelper.GetBranchPoints(method); + var points = _cecilSymbolHelper.GetBranchPoints(method); // assert Assert.NotNull(points); @@ -140,7 +141,7 @@ public void GetBranchPoints_SwitchWithDefault() var method = type.Methods.First(x => x.FullName.Contains($"::{nameof(DeclaredConstructorClass.HasSwitchWithDefault)}")); // act - var points = CecilSymbolHelper.GetBranchPoints(method); + var points = _cecilSymbolHelper.GetBranchPoints(method); // assert Assert.NotNull(points); @@ -163,7 +164,7 @@ public void GetBranchPoints_SwitchWithBreaks() var method = type.Methods.First(x => x.FullName.Contains($"::{nameof(DeclaredConstructorClass.HasSwitchWithBreaks)}")); // act - var points = CecilSymbolHelper.GetBranchPoints(method); + var points = _cecilSymbolHelper.GetBranchPoints(method); // assert Assert.NotNull(points); @@ -186,7 +187,7 @@ public void GetBranchPoints_SwitchWithMultipleCases() var method = type.Methods.First(x => x.FullName.Contains($"::{nameof(DeclaredConstructorClass.HasSwitchWithMultipleCases)}")); // act - var points = CecilSymbolHelper.GetBranchPoints(method); + var points = _cecilSymbolHelper.GetBranchPoints(method); // assert Assert.NotNull(points); @@ -215,7 +216,7 @@ public void GetBranchPoints_AssignsNegativeLineNumberToBranchesInMethodsThatHave var method = type.Methods.First(x => x.FullName.Contains("::Equals")); // act - var points = CecilSymbolHelper.GetBranchPoints(method); + var points = _cecilSymbolHelper.GetBranchPoints(method); // assert Assert.NotNull(points); @@ -239,7 +240,7 @@ public void GetBranchPoints_UsingWithException_Issue243_IgnoresBranchInFinallyBl Assert.True(method.Body.Instructions.First(i => i.OpCode.FlowControl == FlowControl.Cond_Branch).Offset > method.Body.ExceptionHandlers[0].HandlerStart.Offset); // act - var points = CecilSymbolHelper.GetBranchPoints(method); + var points = _cecilSymbolHelper.GetBranchPoints(method); // assert Assert.Empty(points); @@ -255,7 +256,7 @@ public void GetBranchPoints_IgnoresSwitchIn_GeneratedMoveNext() var method = nestedType.Methods.First(x => x.FullName.EndsWith("::MoveNext()")); // act - var points = CecilSymbolHelper.GetBranchPoints(method); + var points = _cecilSymbolHelper.GetBranchPoints(method); // assert Assert.Empty(points); @@ -271,7 +272,7 @@ public void GetBranchPoints_IgnoresBranchesIn_GeneratedMoveNextForSingletonItera var method = nestedType.Methods.First(x => x.FullName.EndsWith("::MoveNext()")); // act - var points = CecilSymbolHelper.GetBranchPoints(method); + var points = _cecilSymbolHelper.GetBranchPoints(method); // assert Assert.Empty(points); @@ -287,7 +288,7 @@ public void GetBranchPoints_IgnoresBranchesIn_AsyncAwaitStateMachine() var method = nestedType.Methods.First(x => x.FullName.EndsWith("::MoveNext()")); // act - var points = CecilSymbolHelper.GetBranchPoints(method); + var points = _cecilSymbolHelper.GetBranchPoints(method); // assert Assert.Empty(points); @@ -300,7 +301,7 @@ public void GetBranchPoints_ExceptionFilter() var type = _module.Types.Single(x => x.FullName == typeof(ExceptionFilter).FullName); var method = type.Methods.Single(x => x.FullName.Contains($"::{nameof(ExceptionFilter.Test)}")); // act - var points = CecilSymbolHelper.GetBranchPoints(method); + var points = _cecilSymbolHelper.GetBranchPoints(method); Assert.Empty(points); }