Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Fixes CoverletSourceRootsMapping issue #1456

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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions Documentation/Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Unreleased

### Fixed
-Could not write lines to file CoverletSourceRootsMapping - in use by another process [#1155](https://github.com/coverlet-coverage/coverlet/issues/1155)
-Incorrect coverage for methods returning IAsyncEnumerable in generic classes [#1383](https://github.com/coverlet-coverage/coverlet/issues/1383)
-Wrong branch coverage for async methods .NET Standard 1.x [#1376](https://github.com/coverlet-coverage/coverlet/issues/1376)
-Empty path exception in visual basic projects [#775](https://github.com/coverlet-coverage/coverlet/issues/775)
Expand Down
4 changes: 2 additions & 2 deletions Documentation/Examples/VSTest/DeterministicBuild/HowTo.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ Add collectors package version generated to `"..\Documentation\Examples\VSTest\D
Go to test project folder and run
```
C:\git\coverlet\Documentation\Examples\VSTest\DeterministicBuild (detbuilddocs -> origin)
λ dotnet test --collect:"XPlat Code Coverage" /p:DeterministicSourcePaths=true
λ dotnet test --collect:"XPlat Code Coverage" /p:DeterministicSourcePaths=true -- DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.DeterministicReport=true
Test run for C:\git\coverlet\Documentation\Examples\VSTest\DeterministicBuild\XUnitTestProject1\bin\Debug\netcoreapp3.1\XUnitTestProject1.dll(.NETCoreApp,Version=v3.1)
Microsoft (R) Test Execution Command Line Tool Version 16.5.0
Copyright (c) Microsoft Corporation. All rights reserved.
Expand All @@ -78,5 +78,5 @@ Total tests: 1
You should see on output folder the coverlet source root mapping file generated.
This is the confirmation that you're running coverage on deterministic build.
```
Documentation\Examples\VSTest\DeterministicBuild\XUnitTestProject1\bin\Debug\netcoreapp3.1\CoverletSourceRootsMapping
Documentation\Examples\VSTest\DeterministicBuild\XUnitTestProject1\bin\Debug\netcoreapp3.1\CoverletSourceRootsMapping_XUnitTestProject1
```
Original file line number Diff line number Diff line change
Expand Up @@ -224,11 +224,13 @@ private static IServiceCollection GetDefaultServiceCollection(TestPlatformEqtTra
serviceCollection.AddTransient<IRetryHelper, RetryHelper>();
serviceCollection.AddTransient<IProcessExitHandler, ProcessExitHandler>();
serviceCollection.AddTransient<IFileSystem, FileSystem>();
serviceCollection.AddTransient<IAssemblyAdapter, AssemblyAdapter>();
serviceCollection.AddTransient<ILogger, CoverletLogger>(_ => new CoverletLogger(eqtTrace, logger));
// We need to keep singleton/static semantics
serviceCollection.AddSingleton<IInstrumentationHelper, InstrumentationHelper>();
// We cache resolutions
serviceCollection.AddSingleton<ISourceRootTranslator, SourceRootTranslator>(serviceProvider => new SourceRootTranslator(testModule, serviceProvider.GetRequiredService<ILogger>(), serviceProvider.GetRequiredService<IFileSystem>()));
serviceCollection.AddSingleton<ISourceRootTranslator, SourceRootTranslator>(serviceProvider =>
new SourceRootTranslator(testModule, serviceProvider.GetRequiredService<ILogger>(), serviceProvider.GetRequiredService<IFileSystem>(), serviceProvider.GetRequiredService<IAssemblyAdapter>()));
serviceCollection.AddSingleton<ICecilSymbolHelper, CecilSymbolHelper>();
return serviceCollection;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ WARNING: DO NOT MODIFY this file unless you are knowledgeable about MSBuild and
<_mapping Include="@(_byProject->'%(Identity)|%(OriginalPath)=%(MappedPath)')" />
</ItemGroup>
<PropertyGroup>
<_sourceRootMappingFilePath>$([MSBuild]::EnsureTrailingSlash('$(OutputPath)'))CoverletSourceRootsMapping</_sourceRootMappingFilePath>
<_sourceRootMappingFilePath>$([MSBuild]::EnsureTrailingSlash('$(OutputPath)'))CoverletSourceRootsMapping_$(AssemblyName)</_sourceRootMappingFilePath>
</PropertyGroup>
<WriteLinesToFile File="$(_sourceRootMappingFilePath)" Lines="@(_mapping)"
Overwrite="true" Encoding="Unicode"
Expand Down
10 changes: 10 additions & 0 deletions src/coverlet.core/Abstractions/IAssemblyAdapter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// 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 IAssemblyAdapter
{
string GetAssemblyName(string assemblyPath);
}
}
16 changes: 16 additions & 0 deletions src/coverlet.core/Helpers/AssemblyAdapter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.Reflection;
using Coverlet.Core.Abstractions;

namespace Coverlet.Core.Helpers
{
internal class AssemblyAdapter : IAssemblyAdapter
{
public string GetAssemblyName(string assemblyPath)
{
return AssemblyName.GetAssemblyName(assemblyPath).Name;
}
}
}
10 changes: 7 additions & 3 deletions src/coverlet.core/Helpers/SourceRootTranslator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ internal class SourceRootTranslator : ISourceRootTranslator
private readonly IFileSystem _fileSystem;
private readonly Dictionary<string, List<SourceRootMapping>> _sourceRootMapping;
private readonly Dictionary<string, List<string>> _sourceToDeterministicPathMapping;
private const string MappingFileName = "CoverletSourceRootsMapping";
private readonly string _mappingFileName;
private Dictionary<string, string> _resolutionCacheFiles;

public SourceRootTranslator(ILogger logger, IFileSystem fileSystem)
Expand All @@ -32,7 +32,7 @@ public SourceRootTranslator(ILogger logger, IFileSystem fileSystem)
_sourceRootMapping = new Dictionary<string, List<SourceRootMapping>>();
}

public SourceRootTranslator(string moduleTestPath, ILogger logger, IFileSystem fileSystem)
public SourceRootTranslator(string moduleTestPath, ILogger logger, IFileSystem fileSystem, IAssemblyAdapter assemblyAdapter)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_fileSystem = fileSystem ?? throw new ArgumentNullException(nameof(fileSystem));
Expand All @@ -44,6 +44,10 @@ public SourceRootTranslator(string moduleTestPath, ILogger logger, IFileSystem f
{
throw new FileNotFoundException($"Module test path '{moduleTestPath}' not found", moduleTestPath);
}

string assemblyName = assemblyAdapter.GetAssemblyName(moduleTestPath);
_mappingFileName = $"CoverletSourceRootsMapping_{assemblyName}";

_sourceRootMapping = LoadSourceRootMapping(Path.GetDirectoryName(moduleTestPath));
_sourceToDeterministicPathMapping = LoadSourceToDeterministicPathMapping(_sourceRootMapping);
}
Expand Down Expand Up @@ -75,7 +79,7 @@ public SourceRootTranslator(string moduleTestPath, ILogger logger, IFileSystem f
{
var mapping = new Dictionary<string, List<SourceRootMapping>>();

string mappingFilePath = Path.Combine(directory, MappingFileName);
string mappingFilePath = Path.Combine(directory, _mappingFileName);
if (!_fileSystem.Exists(mappingFilePath))
{
return mapping;
Expand Down
4 changes: 3 additions & 1 deletion src/coverlet.msbuild.tasks/InstrumentationTask.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,13 @@ public override bool Execute()
IServiceCollection serviceCollection = new ServiceCollection();
serviceCollection.AddTransient<IProcessExitHandler, ProcessExitHandler>();
serviceCollection.AddTransient<IFileSystem, FileSystem>();
serviceCollection.AddTransient<IAssemblyAdapter, AssemblyAdapter>();
serviceCollection.AddTransient<IConsole, SystemConsole>();
serviceCollection.AddTransient<ILogger, MSBuildLogger>(_ => _logger);
serviceCollection.AddTransient<IRetryHelper, RetryHelper>();
// We cache resolutions
serviceCollection.AddSingleton<ISourceRootTranslator, SourceRootTranslator>(serviceProvider => new SourceRootTranslator(Path, serviceProvider.GetRequiredService<ILogger>(), serviceProvider.GetRequiredService<IFileSystem>()));
serviceCollection.AddSingleton<ISourceRootTranslator, SourceRootTranslator>(serviceProvider =>
new SourceRootTranslator(Path, serviceProvider.GetRequiredService<ILogger>(), serviceProvider.GetRequiredService<IFileSystem>(), serviceProvider.GetRequiredService<IAssemblyAdapter>()));
// We need to keep singleton/static semantics
serviceCollection.AddSingleton<IInstrumentationHelper, InstrumentationHelper>();
serviceCollection.AddSingleton<ICecilSymbolHelper, CecilSymbolHelper>();
Expand Down
2 changes: 1 addition & 1 deletion src/coverlet.msbuild.tasks/coverlet.msbuild.targets
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
<_mapping Include="@(_byProject->'%(Identity)|%(OriginalPath)=%(MappedPath)')" />
</ItemGroup>
<PropertyGroup>
<_sourceRootMappingFilePath>$([MSBuild]::EnsureTrailingSlash('$(OutputPath)'))CoverletSourceRootsMapping</_sourceRootMappingFilePath>
<_sourceRootMappingFilePath>$([MSBuild]::EnsureTrailingSlash('$(OutputPath)'))CoverletSourceRootsMapping_$(AssemblyName)</_sourceRootMappingFilePath>
</PropertyGroup>
<WriteLinesToFile File="$(_sourceRootMappingFilePath)" Lines="@(_mapping)"
Overwrite="true" Encoding="Unicode"
Expand Down