diff --git a/FineCodeCoverage/Core/FCCEngine.cs b/FineCodeCoverage/Core/FCCEngine.cs index d4d8b8b0..d413fd6a 100644 --- a/FineCodeCoverage/Core/FCCEngine.cs +++ b/FineCodeCoverage/Core/FCCEngine.cs @@ -258,7 +258,7 @@ Process PropertyGroup settings return settings; } - public static string[] GetSourceFiles(string assemblyName, string className) + public static string[] GetSourceFiles(string assemblyName, string qualifiedClassName) { // Note : There may be more than one file; e.g. in the case of partial classes @@ -271,11 +271,9 @@ public static string[] GetSourceFiles(string assemblyName, string className) return new string[0]; } - var longClassName = $"{assemblyName}.{className}"; - var classFiles = package .Classes.Class - .Where(x => x.Name.Equals(longClassName)) + .Where(x => x.Name.Equals(qualifiedClassName)) .Select(x => x.Filename) .ToArray(); diff --git a/FineCodeCoverage/Core/ReportGenerator/ReportGeneratorUtil.cs b/FineCodeCoverage/Core/ReportGenerator/ReportGeneratorUtil.cs index f603d11f..c137cbf5 100644 --- a/FineCodeCoverage/Core/ReportGenerator/ReportGeneratorUtil.cs +++ b/FineCodeCoverage/Core/ReportGenerator/ReportGeneratorUtil.cs @@ -244,8 +244,6 @@ public static void ProcessCoberturaHtmlFile(string htmlFile, bool darkMode, out var htmlFileContent = File.ReadAllText(htmlFile); - // delete all html files - var folder = Path.GetDirectoryName(htmlFile); // create and save doc util @@ -274,8 +272,50 @@ public static void ProcessCoberturaHtmlFile(string htmlFile, bool darkMode, out try { tableRows[12].SetAttributeValue("style", "display:none"); } catch { } // TEXT changes + var assemblyClassDelimiter = "!"; + var outerHtml = doc.DocumentNode.OuterHtml; + var htmlSb = new StringBuilder(outerHtml); + var assembliesSearch = "var assemblies = ["; + var startIndex = outerHtml.IndexOf(assembliesSearch) + assembliesSearch.Length - 1; + var endIndex = outerHtml.IndexOf("var historicCoverageExecutionTimes"); + var assembliesToReplace = outerHtml.Substring(startIndex, endIndex - startIndex); + endIndex = assembliesToReplace.LastIndexOf(']'); + assembliesToReplace = assembliesToReplace.Substring(0, endIndex + 1); + var assemblies = JArray.Parse(assembliesToReplace); + foreach (JObject assembly in assemblies) + { + var assemblyName = assembly["name"]; + var classes = assembly["classes"] as JArray; + + var autoGeneratedRemovals = new List(); + foreach (JObject @class in classes) + { + var className = @class["name"].ToString(); + if (className == "AutoGeneratedProgram") + { + autoGeneratedRemovals.Add(@class); + } + else + { + // simplify name + var lastIndexOfDotInName = className.LastIndexOf('.'); + if (lastIndexOfDotInName != -1) @class["name"] = className.Substring(lastIndexOfDotInName).Trim('.'); + + //mark with # and add the assembly name + var rp = @class["rp"].ToString(); + var htmlIndex = rp.IndexOf(".html"); + @class["rp"] = $"#{assemblyName}{assemblyClassDelimiter}{className + ".html" + rp.Substring(htmlIndex + 5)}"; + } + + } + foreach (var autoGeneratedRemoval in autoGeneratedRemovals) + { + classes.Remove(autoGeneratedRemoval); + } - var htmlSb = new StringBuilder(doc.DocumentNode.OuterHtml); + } + var assembliesReplaced = assemblies.ToString(); + htmlSb.Replace(assembliesToReplace, assembliesReplaced); htmlSb.Replace(".table-fixed", ".table-fixed-ignore-me"); @@ -357,7 +397,10 @@ public static void ProcessCoberturaHtmlFile(string htmlFile, bool darkMode, out if (event.preventDefault) event.preventDefault() if (event.stopPropagation) event.stopPropagation(); - var classs = classes[href]; + var assemblyAndQualifiedClassName = href.substring(1, htmlExtensionIndex); + var delimiterIndex = assemblyAndQualifiedClassName.indexOf('{assemblyClassDelimiter}'); + var assembly = assemblyAndQualifiedClassName.substring(0, delimiterIndex); + var qualifiedClassName = assemblyAndQualifiedClassName.substring(delimiterIndex + 1); var fileLine = href.substring(htmlExtensionIndex + htmlExtension.length); if (fileLine.indexOf('#') !== -1) @@ -365,7 +408,7 @@ public static void ProcessCoberturaHtmlFile(string htmlFile, bool darkMode, out else fileLine = ['0', '0']; - window.external.OpenFile(classs.assembly.name, classs.name, parseInt(fileLine[0]), parseInt(fileLine[1])); + window.external.OpenFile(assembly, qualifiedClassName, parseInt(fileLine[0]), parseInt(fileLine[1])); return false; }}); diff --git a/FineCodeCoverage/Output/OutputToolWindowControl.xaml.cs b/FineCodeCoverage/Output/OutputToolWindowControl.xaml.cs index 9feaed07..f1e2bd01 100644 --- a/FineCodeCoverage/Output/OutputToolWindowControl.xaml.cs +++ b/FineCodeCoverage/Output/OutputToolWindowControl.xaml.cs @@ -79,15 +79,15 @@ public ScriptManager(DTE dte) [SuppressMessage("Usage", "VSTHRD104:Offer async methods")] [SuppressMessage("Style", "IDE0060:Remove unused parameter")] - public void OpenFile(string assemblyName, string className, int file, int line) + public void OpenFile(string assemblyName, string qualifiedClassName, int file, int line) { // Note : There may be more than one file; e.g. in the case of partial classes - var sourceFiles = FCCEngine.GetSourceFiles(assemblyName, className); + var sourceFiles = FCCEngine.GetSourceFiles(assemblyName, qualifiedClassName); if (!sourceFiles.Any()) { - var message = $"Source File(s) Not Found : [{ assemblyName }]{ className }"; + var message = $"Source File(s) Not Found : [{ assemblyName }]{ qualifiedClassName }"; Logger.Log(message); MessageBox.Show(message); return;