private static void LogResolutionFailuresForAssembly(ParsedTraceFile traceFile, string symbolDirectory, GlobPatternList assemblyPatterns, string assemblyName, AssemblyResolutionCount count) { if (count.unresolvedMethods > 0) { logger.Warn("{count} of {total} ({percentage}) method IDs from assembly {assemblyName} could not be resolved in trace file {traceFile} with symbols from" + " {symbolDirectory} with {assemblyPatterns}. Turn on debug logging to get the exact method IDs." + " This may happen if the corresponding PDB file either could not be found or could not be parsed. Ensure the PDB file for this assembly is" + " in the specified PDB folder where the Upload Daemon looks for it and it is included by the PDB file include/exclude patterns configured for the UploadDaemon. " + " You can exclude this assembly from the coverage analysis to suppress this warning.", count.unresolvedMethods, count.TotalMethods, count.UnresolvedPercentage, assemblyName, traceFile.FilePath, symbolDirectory, assemblyPatterns.Describe()); } if (count.methodsWithoutSourceFile > 0) { logger.Warn("{count} of {total} ({percentage}) method IDs from assembly {assemblyName} do not have a source file in the corresponding PDB file." + " Read from trace file {traceFile} with symbols from" + " {symbolDirectory} with {assemblyPatterns}. Turn on debug logging to get the exact method IDs." + " This sometimes happens and may be an indication of broken PDB files. Please make sure your PDB files are correct." + " You can exclude this assembly from the coverage analysis to suppress this warning.", count.methodsWithoutSourceFile, count.TotalMethods, count.WithoutSourceFilePercentage, assemblyName, traceFile.FilePath, symbolDirectory, assemblyPatterns.Describe()); } if (count.methodsWithoutSourceFile > 0) { logger.Warn("{count} of {total} ({percentage}) method IDs from assembly {assemblyName} contain compiler hidden lines in the corresponding PDB file." + " Read from trace file {traceFile} with symbols from" + " {symbolDirectory} with {assemblyPatterns}. Turn on debug logging to get the exact method IDs." + " This is usually not a problem as the compiler may generate additional code that does not correspond to any source code." + " You can exclude this assembly from the coverage analysis to suppress this warning.", count.methodsWithCompilerHiddenLines, count.TotalMethods, count.WithCompilerHiddenLinesPercentage, assemblyName, traceFile.FilePath, symbolDirectory, assemblyPatterns.Describe()); } }
private static void LogResolutionFailures(ParsedTraceFile traceFile, string symbolDirectory, GlobPatternList assemblyPatterns, Dictionary <string, AssemblyResolutionCount> resolutionCounts) { foreach (string assemblyName in resolutionCounts.Keys) { AssemblyResolutionCount count = resolutionCounts[assemblyName]; LogResolutionFailuresForAssembly(traceFile, symbolDirectory, assemblyPatterns, assemblyName, count); } }
/// <summary> /// Converts the given trace file to a dictionary containing all covered lines of each source file for which /// coverage could be resolved with the PDB files in the given symbol directory. /// /// Public for testing. /// </summary> public static Dictionary <string, FileCoverage> ConvertToLineCoverage(ParsedTraceFile traceFile, SymbolCollection symbolCollection, string symbolDirectory, GlobPatternList assemblyPatterns) { logger.Debug("Converting trace {traceFile} to line coverage", traceFile); Dictionary <string, AssemblyResolutionCount> resolutionCounts = new Dictionary <string, AssemblyResolutionCount>(); Dictionary <string, FileCoverage> lineCoverage = new Dictionary <string, FileCoverage>(); foreach ((string assemblyName, uint methodId) in traceFile.CoveredMethods) { if (!assemblyPatterns.Matches(assemblyName)) { continue; } SymbolCollection.SourceLocation sourceLocation = symbolCollection.Resolve(assemblyName, methodId); if (!resolutionCounts.TryGetValue(assemblyName, out AssemblyResolutionCount count)) { count = new AssemblyResolutionCount(); resolutionCounts[assemblyName] = count; } if (sourceLocation == null) { count.unresolvedMethods += 1; logger.Debug("Could not resolve method ID {methodId} from assembly {assemblyName} in trace file {traceFile}" + " with symbols from {symbolDirectory} with {assemblyPatterns}", methodId, assemblyName, traceFile.FilePath, symbolDirectory, assemblyPatterns.Describe()); continue; } else if (string.IsNullOrEmpty(sourceLocation.SourceFile)) { count.methodsWithoutSourceFile += 1; logger.Debug("Could not resolve source file of method ID {methodId} from assembly {assemblyName} in trace file {traceFile}" + " with symbols from {symbolDirectory} with {assemblyPatterns}", methodId, assemblyName, traceFile.FilePath, symbolDirectory, assemblyPatterns.Describe()); continue; } else if (sourceLocation.StartLine == PdbFile.CompilerHiddenLine || sourceLocation.EndLine == PdbFile.CompilerHiddenLine) { count.methodsWithCompilerHiddenLines += 1; logger.Debug("Resolved lines of method ID {methodId} from assembly {assemblyName} contain compiler hidden lines in trace file {traceFile}" + " with symbols from {symbolDirectory} with {assemblyPatterns}", methodId, assemblyName, traceFile.FilePath, symbolDirectory, assemblyPatterns.Describe()); continue; } count.resolvedMethods += 1; AddToLineCoverage(lineCoverage, sourceLocation); } LogResolutionFailures(traceFile, symbolDirectory, assemblyPatterns, resolutionCounts); return(lineCoverage); }
public void MustSupportNewStyleMethodReferences() { ParsedTraceFile trace = new ParsedTraceFile(new string[] { "Assembly=ProfilerGUI:2 Version:1.0.0.0", $"Inlined=2:12345", }, "cov.txt"); Assert.That(trace.CoveredMethods, Has.Count.EqualTo(1)); Assert.That(trace.CoveredMethods[0].Item1, Is.EqualTo("ProfilerGUI")); Assert.That(trace.CoveredMethods[0].Item2, Is.EqualTo(12345)); }
public void TracesWithoutCoverageShouldResultInNullBeingReturned() { ParsedTraceFile traceFile = new ParsedTraceFile(new string[] { "Assembly=ProfilerGUI:2 Version:1.0.0.0", }, "coverage_12345_1234.txt"); Dictionary <string, FileCoverage> report = new LineCoverageSynthesizer().ConvertToLineCoverage(traceFile, TestUtils.TestDataDirectory, new GlobPatternList(new List <string> { "*" }, new List <string> { })); Assert.That(report, Is.Null); }
public void TestSynthesizing() { ParsedTraceFile traceFile = new ParsedTraceFile(new string[] { "Assembly=ProfilerGUI:2 Version:1.0.0.0", $"Inlined=2:{ExistingMethodToken}", }, "coverage_12345_1234.txt"); string coverageReport = Convert(traceFile, TestUtils.TestDataDirectory, new GlobPatternList(new List <string> { "*" }, new List <string> { })); Assert.That(NormalizeNewLines(coverageReport.Trim()), Is.EqualTo(NormalizeNewLines(@"# isMethodAccurate=true \\VBOXSVR\proj\teamscale-profiler-dotnet\ProfilerGUI\Source\Configurator\MainViewModel.cs 37-39"))); }
public void ExcludingAllPdbsShouldResultInException() { ParsedTraceFile traceFile = new ParsedTraceFile(new string[] { "Assembly=ProfilerGUI:2 Version:1.0.0.0", $"Inlined=2:{ExistingMethodToken}", }, "coverage_12345_1234.txt"); Exception exception = Assert.Throws <LineCoverageSynthesizer.LineCoverageConversionFailedException>(() => { LineCoverageSynthesizerTest.Convert(traceFile, TestUtils.TestDataDirectory, new GlobPatternList(new List <string> { "xx" }, new List <string> { "*" })); }); Assert.That(exception.Message, Contains.Substring("no symbols")); }
/// <inheritdoc/> public Dictionary <string, FileCoverage> ConvertToLineCoverage(ParsedTraceFile traceFile, string symbolDirectory, GlobPatternList assemblyPatterns) { SymbolCollection symbolCollection = symbolCollectionResolver.ResolveFrom(symbolDirectory, assemblyPatterns); if (symbolCollection.IsEmpty) { throw new LineCoverageConversionFailedException($"Failed to convert {traceFile.FilePath} to line coverage." + $" Found no symbols in {symbolDirectory} matching {assemblyPatterns.Describe()}"); } Dictionary <string, FileCoverage> lineCoverage = ConvertToLineCoverage(traceFile, symbolCollection, symbolDirectory, assemblyPatterns); if (lineCoverage.Count == 0 || lineCoverage.Values.All(fileCoverage => fileCoverage.CoveredLineRanges.Count() == 0)) { return(null); } return(lineCoverage); }
public void CompilerHiddenLinesShouldBeIgnored() { ParsedTraceFile traceFile = new ParsedTraceFile(new string[] { "Assembly=Test:2 Version:1.0.0.0", "Inlined=2:1234", }, "coverage_12345_1234.txt"); AssemblyMethodMappings mappings = new AssemblyMethodMappings { AssemblyName = "Test", SymbolFileName = "Test.pdb", }; mappings.MethodMappings.Add(new MethodMapping { MethodToken = 1234, SourceFile = "", StartLine = 16707566, EndLine = 16707566, }); mappings.MethodMappings.Add(new MethodMapping { MethodToken = 1234, SourceFile = @"c:\some\file.cs", StartLine = 16707566, EndLine = 16707566, }); SymbolCollection symbolCollection = new SymbolCollection(new List <AssemblyMethodMappings>() { mappings }); Dictionary <string, FileCoverage> coverage = LineCoverageSynthesizer.ConvertToLineCoverage(traceFile, symbolCollection, TestUtils.TestDataDirectory, new GlobPatternList(new List <string> { "*" }, new List <string> { })); Assert.That(coverage, Is.Empty); }
private static string Convert(ParsedTraceFile traceFile, string symbolDirectory, GlobPatternList assemlyPatterns) { return(LineCoverageSynthesizer.ConvertToLineCoverageReport(new LineCoverageSynthesizer().ConvertToLineCoverage( traceFile, symbolDirectory, assemlyPatterns))); }