Skip to content

Commit 7a19921

Browse files
authored
Merge pull request #164 from tonyhallett/improve-no-hotspots-message
include threshold options in no riskhotspots messge
2 parents 10f3c1f + 3c0a830 commit 7a19921

File tree

1 file changed

+109
-92
lines changed

1 file changed

+109
-92
lines changed

FineCodeCoverage/Core/ReportGenerator/ReportGeneratorUtil.cs

Lines changed: 109 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -31,24 +31,24 @@ internal class ReportGeneratorResult
3131
}
3232

3333
[Export(typeof(IReportGeneratorUtil))]
34-
internal partial class ReportGeneratorUtil: IReportGeneratorUtil
34+
internal partial class ReportGeneratorUtil : IReportGeneratorUtil
3535
{
36-
private readonly IAssemblyUtil assemblyUtil;
37-
private readonly IProcessUtil processUtil;
38-
private readonly ILogger logger;
39-
private readonly IToolFolder toolFolder;
40-
private readonly IToolZipProvider toolZipProvider;
36+
private readonly IAssemblyUtil assemblyUtil;
37+
private readonly IProcessUtil processUtil;
38+
private readonly ILogger logger;
39+
private readonly IToolFolder toolFolder;
40+
private readonly IToolZipProvider toolZipProvider;
4141
private readonly IFileUtil fileUtil;
42-
private readonly IAppOptionsProvider appOptionsProvider;
43-
private const string zipPrefix = "reportGenerator";
42+
private readonly IAppOptionsProvider appOptionsProvider;
43+
private const string zipPrefix = "reportGenerator";
4444
private const string zipDirectoryName = "reportGenerator";
4545

46-
public string ReportGeneratorExePath { get; private set; }
46+
public string ReportGeneratorExePath { get; private set; }
4747

4848
[ImportingConstructor]
4949
public ReportGeneratorUtil(
5050
IAssemblyUtil assemblyUtil,
51-
IProcessUtil processUtil,
51+
IProcessUtil processUtil,
5252
ILogger logger,
5353
IToolFolder toolFolder,
5454
IToolZipProvider toolZipProvider,
@@ -57,13 +57,13 @@ IAppOptionsProvider appOptionsProvider
5757
)
5858
{
5959
this.fileUtil = fileUtil;
60-
this.appOptionsProvider = appOptionsProvider;
61-
this.assemblyUtil = assemblyUtil;
62-
this.processUtil = processUtil;
63-
this.logger = logger;
64-
this.toolFolder = toolFolder;
65-
this.toolZipProvider = toolZipProvider;
66-
}
60+
this.appOptionsProvider = appOptionsProvider;
61+
this.assemblyUtil = assemblyUtil;
62+
this.processUtil = processUtil;
63+
this.logger = logger;
64+
this.toolFolder = toolFolder;
65+
this.toolZipProvider = toolZipProvider;
66+
}
6767

6868
public void Initialize(string appDataFolder)
6969
{
@@ -72,7 +72,7 @@ public void Initialize(string appDataFolder)
7272
?? Directory.GetFiles(zipDestination, "*reportGenerator*.exe", SearchOption.AllDirectories).FirstOrDefault();
7373
}
7474

75-
public async Task<ReportGeneratorResult> GenerateAsync(IEnumerable<string> coverOutputFiles,string reportOutputFolder, bool darkMode, bool throwError = false)
75+
public async Task<ReportGeneratorResult> GenerateAsync(IEnumerable<string> coverOutputFiles, string reportOutputFolder, bool darkMode, bool throwError = false)
7676
{
7777
var title = "ReportGenerator Run";
7878

@@ -82,7 +82,7 @@ public async Task<ReportGeneratorResult> GenerateAsync(IEnumerable<string> cover
8282
var reportGeneratorSettings = new List<string>();
8383

8484
reportGeneratorSettings.Add($@"""-targetdir:{reportOutputFolder}""");
85-
85+
8686
async Task<bool> run(string outputReportType, string inputReports)
8787
{
8888
var reportTypeSettings = reportGeneratorSettings.ToArray().ToList();
@@ -91,17 +91,14 @@ async Task<bool> run(string outputReportType, string inputReports)
9191
{
9292
reportTypeSettings.Add($@"""-reports:{inputReports}""");
9393
reportTypeSettings.Add($@"""-reporttypes:Cobertura""");
94-
94+
9595
}
9696
else if (outputReportType.Equals("HtmlInline_AzurePipelines", StringComparison.OrdinalIgnoreCase))
9797
{
9898
reportTypeSettings.Add($@"""-reports:{inputReports}""");
9999
reportTypeSettings.Add($@"""-plugins:{typeof(FccLightReportBuilder).Assembly.Location}""");
100100
reportTypeSettings.Add($@"""-reporttypes:{(darkMode ? FccDarkReportBuilder.REPORT_TYPE : FccLightReportBuilder.REPORT_TYPE)}""");
101-
var options = appOptionsProvider.Get();
102-
var cyclomaticThreshold = options.ThresholdForCyclomaticComplexity;
103-
var crapScoreThreshold = options.ThresholdForCrapScore;
104-
var nPathThreshold = options.ThresholdForNPathComplexity;
101+
var (cyclomaticThreshold, crapScoreThreshold, nPathThreshold) = HotspotThresholds();
105102
106103
reportTypeSettings.Add($@"""riskHotspotsAnalysisThresholds:metricThresholdForCyclomaticComplexity={cyclomaticThreshold}""");
107104
reportTypeSettings.Add($@"""riskHotspotsAnalysisThresholds:metricThresholdForCrapScore={crapScoreThreshold}""");
@@ -122,10 +119,10 @@ async Task<bool> run(string outputReportType, string inputReports)
122119
Arguments = string.Join(" ", reportTypeSettings),
123120
WorkingDirectory = reportOutputFolder
124121
});
125-
126122
127-
if(result != null)
128-
{
123+
124+
if (result != null)
125+
{
129126
if (result.ExitCode != 0)
130127
{
131128
logger.Log($"{title} [reporttype:{outputReportType}] Error", result.Output);
@@ -143,11 +140,11 @@ async Task<bool> run(string outputReportType, string inputReports)
143140
return true;
144141
}
145142
return false;
146-
143+
147144
}
148-
145+
149146
var reportGeneratorResult = new ReportGeneratorResult { Success = false, UnifiedHtml = null, UnifiedXmlFile = unifiedXmlFile };
150-
147+
151148
var coberturaResult = await run("Cobertura", string.Join(";", coverOutputFiles));
152149
153150
if (coberturaResult)
@@ -157,18 +154,23 @@ async Task<bool> run(string outputReportType, string inputReports)
157154
{
158155
reportGeneratorResult.UnifiedHtml = fileUtil.ReadAllText(unifiedHtmlFile);
159156
reportGeneratorResult.Success = true;
160-
}
161-
157+
}
158+
162159
}
163160
164161
return reportGeneratorResult;
165-
162+
166163
}
167164
168165
public string ProcessUnifiedHtml(string htmlForProcessing, string reportOutputFolder, bool darkMode)
169166
{
170167
return assemblyUtil.RunInAssemblyResolvingContext(() =>
171168
{
169+
var (cyclomaticThreshold, crapScoreThreshold, nPathThreshold) = HotspotThresholds();
170+
var noRiskHotspotsHeader = "No risk hotspots that exceed options :";
171+
var noRiskHotspotsCyclomaticMsg = $"Cyclomatic complexity : {cyclomaticThreshold}";
172+
var noRiskHotspotsNpathMsg =$"NPath complexity : {nPathThreshold}";
173+
var noRiskHotspotsCrapMessage = $"Crap score : {crapScoreThreshold}";
172174
var doc = new HtmlDocument();
173175
174176
doc.OptionFixNestedTags = true;
@@ -181,7 +183,7 @@ public string ProcessUnifiedHtml(string htmlForProcessing, string reportOutputFo
181183
doc.DocumentNode.QuerySelectorAll(".container").ToList().ForEach(x => x.SetAttributeValue("style", "margin:0;padding:0;border:0"));
182184
doc.DocumentNode.QuerySelectorAll(".containerleft").ToList().ForEach(x => x.SetAttributeValue("style", "margin:0;padding:0;border:0"));
183185
doc.DocumentNode.QuerySelectorAll(".containerleft > h1 , .containerleft > p").ToList().ForEach(x => x.SetAttributeValue("style", "display:none"));
184-
186+
185187
// DOM changes
186188
187189
var table = doc.DocumentNode.QuerySelectorAll("table.overview").First();
@@ -242,29 +244,29 @@ public string ProcessUnifiedHtml(string htmlForProcessing, string reportOutputFo
242244
var assembliesReplaced = assemblies.ToString();
243245
htmlSb.Replace(assembliesToReplace, assembliesReplaced);
244246
245-
//is this even present if there are no riskhotspots
246-
var riskHotspotsSearch = "var riskHotspots = [";
247-
var rhStartIndex = outerHtml.IndexOf(riskHotspotsSearch) + riskHotspotsSearch.Length - 1;
248-
var rhEndIndex = outerHtml.IndexOf("var branchCoverageAvailable");
249-
var rhToReplace = outerHtml.Substring(rhStartIndex, rhEndIndex - rhStartIndex);
250-
rhEndIndex = rhToReplace.LastIndexOf(']');
251-
rhToReplace = rhToReplace.Substring(0, rhEndIndex + 1);
252-
253-
var riskHotspots = JArray.Parse(rhToReplace);
254-
foreach (JObject riskHotspot in riskHotspots)
255-
{
256-
var assembly = riskHotspot["assembly"].ToString();
257-
var qualifiedClassName = riskHotspot["class"].ToString();
247+
//is this even present if there are no riskhotspots
248+
var riskHotspotsSearch = "var riskHotspots = [";
249+
var rhStartIndex = outerHtml.IndexOf(riskHotspotsSearch) + riskHotspotsSearch.Length - 1;
250+
var rhEndIndex = outerHtml.IndexOf("var branchCoverageAvailable");
251+
var rhToReplace = outerHtml.Substring(rhStartIndex, rhEndIndex - rhStartIndex);
252+
rhEndIndex = rhToReplace.LastIndexOf(']');
253+
rhToReplace = rhToReplace.Substring(0, rhEndIndex + 1);
254+
255+
var riskHotspots = JArray.Parse(rhToReplace);
256+
foreach (JObject riskHotspot in riskHotspots)
257+
{
258+
var assembly = riskHotspot["assembly"].ToString();
259+
var qualifiedClassName = riskHotspot["class"].ToString();
258260
// simplify name
259261
var lastIndexOfDotInName = qualifiedClassName.LastIndexOf('.');
260262
if (lastIndexOfDotInName != -1) riskHotspot["class"] = qualifiedClassName.Substring(lastIndexOfDotInName).Trim('.');
261263
var newReportPath = $"#{assembly}{assemblyClassDelimiter}{qualifiedClassName}.html";
262-
riskHotspot["reportPath"] = newReportPath;
263-
}
264-
var riskHotspotsReplaced = riskHotspots.ToString();
265-
htmlSb.Replace(rhToReplace, riskHotspotsReplaced);
264+
riskHotspot["reportPath"] = newReportPath;
265+
}
266+
var riskHotspotsReplaced = riskHotspots.ToString();
267+
htmlSb.Replace(rhToReplace, riskHotspotsReplaced);
266268
267-
htmlSb.Replace(".table-fixed", ".table-fixed-ignore-me");
269+
htmlSb.Replace(".table-fixed", ".table-fixed-ignore-me");
268270
269271
htmlSb.Replace("</head>", $@"
270272
<style type=""text/css"">
@@ -391,23 +393,23 @@ public string ProcessUnifiedHtml(string htmlForProcessing, string reportOutputFo
391393
");
392394
}
393395
394-
htmlSb.Replace("<body>", @"
396+
htmlSb.Replace("<body>", $@"
395397
<body oncontextmenu='return false;'>
396398
<style>
397399
398-
table#headerTabs td {
400+
table#headerTabs td {{
399401
border-width:3px;
400402
padding: 3px;
401403
padding-left: 7px;
402404
padding-right: 7px;
403-
}
404-
table#headerTabs td.tab {
405+
}}
406+
table#headerTabs td.tab {{
405407
cursor: pointer;
406-
}
407-
table#headerTabs td.active {
408+
}}
409+
table#headerTabs td.active {{
408410
border-bottom: 3px solid transparent;
409411
font-weight: bolder;
410-
}
412+
}}
411413
412414
</style>
413415
<script>
@@ -416,25 +418,25 @@ public string ProcessUnifiedHtml(string htmlForProcessing, string reportOutputFo
416418
body.style['padding-top'] = '50px';
417419
418420
var tabs = [
419-
{ button: 'btnCoverage', content: 'coverage-info' },
420-
{ button: 'btnSummary', content: 'table-fixed' },
421-
{ button: 'btnRiskHotspots', content: 'risk-hotspots' },
421+
{{ button: 'btnCoverage', content: 'coverage-info' }},
422+
{{ button: 'btnSummary', content: 'table-fixed' }},
423+
{{ button: 'btnRiskHotspots', content: 'risk-hotspots' }},
422424
];
423425
424426
var riskHotspotsTable;
425427
var riskHotspotsElement;
426428
var addedFileIndexToRiskHotspots = false;
427-
var addFileIndexToRiskHotspotsClassLink = function(){
428-
if(!addedFileIndexToRiskHotspots){
429+
var addFileIndexToRiskHotspotsClassLink = function(){{
430+
if(!addedFileIndexToRiskHotspots){{
429431
addedFileIndexToRiskHotspots = true;
430432
var riskHotspotsElements = document.getElementsByTagName('risk-hotspots');
431433
if(riskHotspotsElements.length == 1){{
432434
riskHotspotsElement = riskHotspotsElements[0];
433435
riskHotspotsTable = riskHotspotsElement.querySelector('table');
434-
if(riskHotspotsTable){
436+
if(riskHotspotsTable){{
435437
var rhBody = riskHotspotsTable.querySelector('tbody');
436438
var rows = rhBody.rows;
437-
for(var i=0;i<rows.length;i++){
439+
for(var i=0;i<rows.length;i++){{
438440
var row = rows[i];
439441
var cells = row.cells;
440442
var classCell = cells[1];
@@ -449,48 +451,52 @@ public string ProcessUnifiedHtml(string htmlForProcessing, string reportOutputFo
449451
var file = fileAndLine[0];
450452
var line = fileAndLine[1];
451453
classLink.href = classLink.hash + '#file' + file + '_line0';
452-
}
453-
}
454+
}}
455+
}}
454456
455457
}}
456-
}
457-
}
458+
}}
459+
}}
458460
459461
// necessary for WebBrowser
460-
function removeElement(element){
462+
function removeElement(element){{
461463
element.parentNode.removeChild(element);
462-
}
464+
}}
463465
464-
function insertAfter(newNode, existingNode) {
466+
function insertAfter(newNode, existingNode) {{
465467
existingNode.parentNode.insertBefore(newNode, existingNode.nextSibling);
466-
}
468+
}}
467469
468470
var noHotspotsMessage
469-
var addNoRiskHotspotsMessageIfRequired = function(){
470-
if(riskHotspotsTable == null){
471+
var addNoRiskHotspotsMessageIfRequired = function(){{
472+
if(riskHotspotsTable == null){{
471473
noHotspotsMessage = document.createElement(""p"");
472474
noHotspotsMessage.style.margin = ""0"";
473-
noHotspotsMessage.innerText = ""No risk hotspots found."";
475+
var header = ""{noRiskHotspotsHeader}"";
476+
var cyclomaticMessage = ""{noRiskHotspotsCyclomaticMsg}"";
477+
var crapMessage =""{noRiskHotspotsCrapMessage}"";
478+
var nPathMessage = ""{noRiskHotspotsNpathMsg}"";
479+
noHotspotsMessage.innerText = header + ""\n"" + cyclomaticMessage + ""\n"" + crapMessage + ""\n"" + nPathMessage;
474480
475481
insertAfter(noHotspotsMessage, riskHotspotsElement);
476-
}
477-
}
482+
}}
483+
}}
478484
479-
var removeNoRiskHotspotsMessage = function(){
480-
if(noHotspotsMessage){
485+
var removeNoRiskHotspotsMessage = function(){{
486+
if(noHotspotsMessage){{
481487
removeElement(noHotspotsMessage);
482488
noHotspotsMessage = null;
483-
}
484-
}
489+
}}
490+
}}
485491
486-
var openTab = function (tabIndex) {
492+
var openTab = function (tabIndex) {{
487493
if(tabIndex==2){{
488494
addFileIndexToRiskHotspotsClassLink();
489495
addNoRiskHotspotsMessageIfRequired();
490496
}}else{{
491497
removeNoRiskHotspotsMessage();
492498
}}
493-
for (var i = 0; i < tabs.length; i++) {
499+
for (var i = 0; i < tabs.length; i++) {{
494500
495501
var tab = tabs[i];
496502
if (!tab) continue;
@@ -502,19 +508,19 @@ var noHotspotsMessage
502508
if (!content) content = document.getElementsByClassName(tab.content)[0];
503509
if (!content) continue;
504510
505-
if (i == tabIndex) {
511+
if (i == tabIndex) {{
506512
if (button.className.indexOf('active') == -1) button.className += ' active';
507513
content.style.display = 'block';
508-
} else {
514+
}} else {{
509515
button.className = button.className.replace('active', '');
510516
content.style.display = 'none';
511-
}
512-
}
513-
};
517+
}}
518+
}}
519+
}};
514520
515-
window.addEventListener('load', function() {
521+
window.addEventListener('load', function() {{
516522
openTab(0);
517-
});
523+
}});
518524
519525
</script>
520526
<div id='divHeader' style='border-collapse:collapse;padding:0;padding-top:3px;margin:0;border:0;position:fixed;top:0;left:0;width:100%;z-index:100' cellpadding='0' cellspacing='0'>
@@ -618,5 +624,16 @@ Risk Hotspots
618624

619625
});
620626
}
627+
628+
private (int cyclomaticThreshold, int crapScoreThreshold, int nPathThreshold) HotspotThresholds()
629+
{
630+
var options = appOptionsProvider.Get();
631+
return (
632+
options.ThresholdForCyclomaticComplexity,
633+
options.ThresholdForCrapScore,
634+
options.ThresholdForNPathComplexity
635+
);
636+
637+
}
621638
}
622639
}

0 commit comments

Comments
 (0)