diff --git a/src/coverlet.core/Abstractions/ISourceRootTranslator.cs b/src/coverlet.core/Abstractions/ISourceRootTranslator.cs index f64907b..4af6cfd 100644 --- a/src/coverlet.core/Abstractions/ISourceRootTranslator.cs +++ b/src/coverlet.core/Abstractions/ISourceRootTranslator.cs @@ -8,6 +8,7 @@ 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); diff --git a/src/coverlet.core/Helpers/InstrumentationHelper.cs b/src/coverlet.core/Helpers/InstrumentationHelper.cs index a953273..fcf9f4f 100644 --- a/src/coverlet.core/Helpers/InstrumentationHelper.cs +++ b/src/coverlet.core/Helpers/InstrumentationHelper.cs @@ -90,14 +90,32 @@ namespace Coverlet.Core.Helpers if (entry.Type == DebugDirectoryEntryType.CodeView) { CodeViewDebugDirectoryData codeViewData = peReader.ReadCodeViewDebugDirectoryData(entry); - if (_sourceRootTranslator.ResolveFilePath(codeViewData.Path) == $"{Path.GetFileNameWithoutExtension(module)}.pdb") + string modulePdbFileName = $"{Path.GetFileNameWithoutExtension(module)}.pdb"; + if (_sourceRootTranslator.ResolveFilePath(codeViewData.Path) == modulePdbFileName) { // PDB is embedded embedded = true; return true; } - return _fileSystem.Exists(_sourceRootTranslator.ResolveFilePath(codeViewData.Path)); + 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; + } } } diff --git a/src/coverlet.core/Helpers/SourceRootTranslator.cs b/src/coverlet.core/Helpers/SourceRootTranslator.cs index 4d50fbf..5bdef76 100644 --- a/src/coverlet.core/Helpers/SourceRootTranslator.cs +++ b/src/coverlet.core/Helpers/SourceRootTranslator.cs @@ -108,6 +108,17 @@ namespace Coverlet.Core.Helpers return mapping; } + public bool AddMappingInCache(string originalFileName, string targetFileName) + { + if (_resolutionCacheFiles != null && _resolutionCacheFiles.ContainsKey(originalFileName)) + { + return false; + } + + (_resolutionCacheFiles ??= new Dictionary()).Add(originalFileName, targetFileName); + return true; + } + public IReadOnlyList ResolvePathRoot(string pathRoot) { return _sourceRootMapping.TryGetValue(pathRoot, out List sourceRootMapping) ? sourceRootMapping.AsReadOnly() : null; diff --git a/test/coverlet.core.tests/Helpers/InstrumentationHelperTests.cs b/test/coverlet.core.tests/Helpers/InstrumentationHelperTests.cs index d0883ae..c6feee2 100644 --- a/test/coverlet.core.tests/Helpers/InstrumentationHelperTests.cs +++ b/test/coverlet.core.tests/Helpers/InstrumentationHelperTests.cs @@ -54,12 +54,27 @@ namespace Coverlet.Core.Helpers.Tests } [Fact] - public void TestHasPdb() + public void TestHasPdbOfLocalAssembly() { Assert.True(_instrumentationHelper.HasPdb(typeof(InstrumentationHelperTests).Assembly.Location, out bool embeddedPdb)); Assert.False(embeddedPdb); } + [Fact] + public void TestHasPdbOfExternalAssembly() + { + string testAssemblyLocation = GetType().Assembly.Location; + + string externalAssemblyFileName = Path.Combine( + Path.GetDirectoryName(testAssemblyLocation), + "TestAssets", + "75d9f96508d74def860a568f426ea4a4.dll" + ); + + Assert.True(_instrumentationHelper.HasPdb(externalAssemblyFileName, out bool embeddedPdb)); + Assert.False(embeddedPdb); + } + [Fact] public void TestBackupOriginalModule() {