@@ -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