From ab77860fea814c3784ecc73777e15820921dce2b Mon Sep 17 00:00:00 2001 From: Tony Hallett Date: Wed, 7 Jul 2021 16:20:00 +0000 Subject: [PATCH 1/3] fix --- .../ReportGenerator/ReportGeneratorUtil.cs | 38 +++++++++++++++++-- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/FineCodeCoverage/Core/ReportGenerator/ReportGeneratorUtil.cs b/FineCodeCoverage/Core/ReportGenerator/ReportGeneratorUtil.cs index 3785b6bb..6bf8007a 100644 --- a/FineCodeCoverage/Core/ReportGenerator/ReportGeneratorUtil.cs +++ b/FineCodeCoverage/Core/ReportGenerator/ReportGeneratorUtil.cs @@ -407,14 +407,16 @@ public string ProcessUnifiedHtml(string htmlForProcessing, string reportOutputFo { button: 'btnRiskHotspots', content: 'risk-hotspots' }, ]; + var riskHotspotsTable; + var riskHotspotsElement; var addedFileIndexToRiskHotspots = false; var addFileIndexToRiskHotspotsClassLink = function(){ if(!addedFileIndexToRiskHotspots){ addedFileIndexToRiskHotspots = true; var riskHotspotsElements = document.getElementsByTagName('risk-hotspots'); if(riskHotspotsElements.length == 1){{ - var riskHotspotsElement = riskHotspotsElements[0]; - var riskHotspotsTable = riskHotspotsElement.querySelector('table'); + riskHotspotsElement = riskHotspotsElements[0]; + riskHotspotsTable = riskHotspotsElement.querySelector('table'); if(riskHotspotsTable){ var rhBody = riskHotspotsTable.querySelector('tbody'); var rows = rhBody.rows; @@ -439,10 +441,40 @@ public string ProcessUnifiedHtml(string htmlForProcessing, string reportOutputFo }} } } + + // necessary for WebBrowser + function removeElement(element){ + element.parentNode.removeChild(element); + } + + function insertAfter(newNode, existingNode) { + existingNode.parentNode.insertBefore(newNode, existingNode.nextSibling); + } + + var noHotspotsMessage + var addNoRiskHotspotsMessageIfRequired = function(){ + if(riskHotspotsTable == null){ + noHotspotsMessage = document.createElement(""p""); + noHotspotsMessage.style.margin = ""0""; + noHotspotsMessage.innerText = ""No risk hotspots found.""; + + insertAfter(noHotspotsMessage, riskHotspotsElement); + } + } + + var removeNoRiskHotspotsMessage = function(){ + if(noHotspotsMessage){ + removeElement(noHotspotsMessage); + noHotspotsMessage = null; + } + } - var openTab = function (tabIndex) { + var openTab = function (tabIndex) { if(tabIndex==2){{ addFileIndexToRiskHotspotsClassLink(); + addNoRiskHotspotsMessageIfRequired(); + }}else{{ + removeNoRiskHotspotsMessage(); }} for (var i = 0; i < tabs.length; i++) { From d1833f65b5895c00c1b2f6d5bba42253670a8ba3 Mon Sep 17 00:00:00 2001 From: Tony Hallett Date: Thu, 8 Jul 2021 10:11:50 +0000 Subject: [PATCH 2/3] options for risk hotspot thresholds --- .../Core/ReportGenerator/ReportGeneratorUtil.cs | 17 +++++++++++++++-- FineCodeCoverage/Options/AppOptions.cs | 11 +++++++++++ FineCodeCoverage/Options/IAppOptions.cs | 3 +++ README.md | 6 ++++++ 4 files changed, 35 insertions(+), 2 deletions(-) diff --git a/FineCodeCoverage/Core/ReportGenerator/ReportGeneratorUtil.cs b/FineCodeCoverage/Core/ReportGenerator/ReportGeneratorUtil.cs index 6bf8007a..66baf8ea 100644 --- a/FineCodeCoverage/Core/ReportGenerator/ReportGeneratorUtil.cs +++ b/FineCodeCoverage/Core/ReportGenerator/ReportGeneratorUtil.cs @@ -6,6 +6,7 @@ using System.Text; using System.Threading.Tasks; using FineCodeCoverage.Core.Utilities; +using FineCodeCoverage.Options; using Fizzler.Systems.HtmlAgilityPack; using HtmlAgilityPack; using Newtonsoft.Json; @@ -38,7 +39,8 @@ internal partial class ReportGeneratorUtil: IReportGeneratorUtil private readonly IToolFolder toolFolder; private readonly IToolZipProvider toolZipProvider; private readonly IFileUtil fileUtil; - private const string zipPrefix = "reportGenerator"; + private readonly IAppOptionsProvider appOptionsProvider; + private const string zipPrefix = "reportGenerator"; private const string zipDirectoryName = "reportGenerator"; public string ReportGeneratorExePath { get; private set; } @@ -50,10 +52,12 @@ public ReportGeneratorUtil( ILogger logger, IToolFolder toolFolder, IToolZipProvider toolZipProvider, - IFileUtil fileUtil + IFileUtil fileUtil, + IAppOptionsProvider appOptionsProvider ) { this.fileUtil = fileUtil; + this.appOptionsProvider = appOptionsProvider; this.assemblyUtil = assemblyUtil; this.processUtil = processUtil; this.logger = logger; @@ -87,6 +91,15 @@ async Task run(string outputReportType, string inputReports) { reportTypeSettings.Add($@"""-reports:{inputReports}"""); reportTypeSettings.Add($@"""-reporttypes:Cobertura"""); + var options = appOptionsProvider.Get(); + var cyclomaticThreshold = options.ThresholdForCyclomaticComplexity; + var crapScoreThreshold = options.ThresholdForCrapScore; + var nPathThreshold = options.ThresholdForNPathComplexity; + + reportTypeSettings.Add($@"""-riskHotspotsAnalysisThresholds:metricThresholdForCyclomaticComplexity={cyclomaticThreshold}"""); + reportTypeSettings.Add($@"""-riskHotspotsAnalysisThresholds:metricThresholdForCrapScore={crapScoreThreshold}"""); + reportTypeSettings.Add($@"""-riskHotspotsAnalysisThresholds:metricThresholdForNPathComplexity={nPathThreshold}"""); + } else if (outputReportType.Equals("HtmlInline_AzurePipelines", StringComparison.OrdinalIgnoreCase)) { diff --git a/FineCodeCoverage/Options/AppOptions.cs b/FineCodeCoverage/Options/AppOptions.cs index cb617714..9f3128d0 100644 --- a/FineCodeCoverage/Options/AppOptions.cs +++ b/FineCodeCoverage/Options/AppOptions.cs @@ -13,6 +13,7 @@ internal class AppOptions : DialogPage, IAppOptions private const string coverletCategory = "Coverlet"; private const string openCoverCategory = "OpenCover"; private const string outputCategory = "Output"; + private const string reportCategory = "Report"; public AppOptions():this(false) { @@ -137,6 +138,16 @@ You can also ignore additional attributes by adding to this list (short name or [Category(outputCategory)] public string FCCSolutionOutputDirectoryName { get; set; } + [Category(reportCategory)] + [Description("When cyclomatic complexity exceeds this value for a method then the method will be present in the risk hotspots tab.")] + public int ThresholdForCyclomaticComplexity { get; set; } = 30 + [Category(reportCategory)] + [Description("When npath complexity exceeds this value for a method then the method will be present in the risk hotspots tab. OpenCover only")] + public int ThresholdForNPathComplexity { get; set; } = 200 + [Category(reportCategory)] + [Description("When crap score exceeds this value for a method then the method will be present in the risk hotspots tab. OpenCover only")] + public int ThresholdForCrapScore { get; set; } = 15 + [SuppressMessage("Usage", "VSTHRD010:Invoke single-threaded types on Main thread")] public override void SaveSettingsToStorage() { diff --git a/FineCodeCoverage/Options/IAppOptions.cs b/FineCodeCoverage/Options/IAppOptions.cs index a754e329..126cbd6b 100644 --- a/FineCodeCoverage/Options/IAppOptions.cs +++ b/FineCodeCoverage/Options/IAppOptions.cs @@ -18,5 +18,8 @@ public interface IAppOptions string CoverletCollectorDirectoryPath { get; } string OpenCoverCustomPath { get; } string FCCSolutionOutputDirectoryName { get; } + int ThresholdForCyclomaticComplexity { get; } + int ThresholdForNPathComplexity { get; } + int ThresholdForCrapScore { get; } } } \ No newline at end of file diff --git a/README.md b/README.md index 8dbdce63..975d16d3 100644 --- a/README.md +++ b/README.md @@ -121,6 +121,10 @@ ExcludeByFile Glob patterns specifying source files to exclude e.g. **/Migra ExcludeByAttribute Attributes to exclude from code coverage (multiple values) IncludeTestAssembly Specifies whether to report code coverage of the test assembly +ThresholdForCyclomaticComplexity When [cyclomatic complexity](https://en.wikipedia.org/wiki/Cyclomatic_complexity) exceeds this value for a method then the method will be present in the risk hotspots tab. +ThresholdForNPathComplexity When [npath complexity](https://en.wikipedia.org/wiki/Cyclomatic_complexity) exceeds this value for a method then the method will be present in the risk hotspots tab. OpenCover only. +ThresholdForCrapScore When [crap score](https://testing.googleblog.com/2011/02/this-code-is-crap.html) exceeds this value for a method then the method will be present in the risk hotspots tab. OpenCover only. + RunSettingsOnly Specify false for global and project options to be used for coverlet data collector configuration elements when not specified in runsettings CoverletCollectorDirectoryPath Specify path to directory containing coverlet collector files if you need functionality that the FCC version does not provide. @@ -138,6 +142,8 @@ You can ignore a method or an entire class from code coverage by creating and ap You can also ignore additional attributes by adding to the 'ExcludeByAttributes' list (short name or full name supported) e.g. : [GeneratedCode] => Present in System.CodeDom.Compiler namespace [MyCustomExcludeFromCodeCoverage] => Any custom attribute that you may define + + ``` #### Filter Expressions From 51c2ecfe27e33d675bcf5da2afe9c0351d3c15fe Mon Sep 17 00:00:00 2001 From: Tony Hallett Date: Thu, 8 Jul 2021 11:06:52 +0000 Subject: [PATCH 3/3] correct report threshold command line --- .../Core/ReportGenerator/ReportGeneratorUtil.cs | 17 +++++++++-------- FineCodeCoverage/Options/AppOptions.cs | 8 +++++--- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/FineCodeCoverage/Core/ReportGenerator/ReportGeneratorUtil.cs b/FineCodeCoverage/Core/ReportGenerator/ReportGeneratorUtil.cs index 66baf8ea..61799fc8 100644 --- a/FineCodeCoverage/Core/ReportGenerator/ReportGeneratorUtil.cs +++ b/FineCodeCoverage/Core/ReportGenerator/ReportGeneratorUtil.cs @@ -91,21 +91,22 @@ async Task run(string outputReportType, string inputReports) { reportTypeSettings.Add($@"""-reports:{inputReports}"""); reportTypeSettings.Add($@"""-reporttypes:Cobertura"""); - var options = appOptionsProvider.Get(); - var cyclomaticThreshold = options.ThresholdForCyclomaticComplexity; - var crapScoreThreshold = options.ThresholdForCrapScore; - var nPathThreshold = options.ThresholdForNPathComplexity; - reportTypeSettings.Add($@"""-riskHotspotsAnalysisThresholds:metricThresholdForCyclomaticComplexity={cyclomaticThreshold}"""); - reportTypeSettings.Add($@"""-riskHotspotsAnalysisThresholds:metricThresholdForCrapScore={crapScoreThreshold}"""); - reportTypeSettings.Add($@"""-riskHotspotsAnalysisThresholds:metricThresholdForNPathComplexity={nPathThreshold}"""); - } else if (outputReportType.Equals("HtmlInline_AzurePipelines", StringComparison.OrdinalIgnoreCase)) { reportTypeSettings.Add($@"""-reports:{inputReports}"""); reportTypeSettings.Add($@"""-plugins:{typeof(FccLightReportBuilder).Assembly.Location}"""); reportTypeSettings.Add($@"""-reporttypes:{(darkMode ? FccDarkReportBuilder.REPORT_TYPE : FccLightReportBuilder.REPORT_TYPE)}"""); + var options = appOptionsProvider.Get(); + var cyclomaticThreshold = options.ThresholdForCyclomaticComplexity; + var crapScoreThreshold = options.ThresholdForCrapScore; + var nPathThreshold = options.ThresholdForNPathComplexity; + + reportTypeSettings.Add($@"""riskHotspotsAnalysisThresholds:metricThresholdForCyclomaticComplexity={cyclomaticThreshold}"""); + reportTypeSettings.Add($@"""riskHotspotsAnalysisThresholds:metricThresholdForCrapScore={crapScoreThreshold}"""); + reportTypeSettings.Add($@"""riskHotspotsAnalysisThresholds:metricThresholdForNPathComplexity={nPathThreshold}"""); + } else { diff --git a/FineCodeCoverage/Options/AppOptions.cs b/FineCodeCoverage/Options/AppOptions.cs index 9f3128d0..729a6ed5 100644 --- a/FineCodeCoverage/Options/AppOptions.cs +++ b/FineCodeCoverage/Options/AppOptions.cs @@ -140,13 +140,15 @@ You can also ignore additional attributes by adding to this list (short name or [Category(reportCategory)] [Description("When cyclomatic complexity exceeds this value for a method then the method will be present in the risk hotspots tab.")] - public int ThresholdForCyclomaticComplexity { get; set; } = 30 + public int ThresholdForCyclomaticComplexity { get; set; } = 30; + [Category(reportCategory)] [Description("When npath complexity exceeds this value for a method then the method will be present in the risk hotspots tab. OpenCover only")] - public int ThresholdForNPathComplexity { get; set; } = 200 + public int ThresholdForNPathComplexity { get; set; } = 200; + [Category(reportCategory)] [Description("When crap score exceeds this value for a method then the method will be present in the risk hotspots tab. OpenCover only")] - public int ThresholdForCrapScore { get; set; } = 15 + public int ThresholdForCrapScore { get; set; } = 15; [SuppressMessage("Usage", "VSTHRD010:Invoke single-threaded types on Main thread")] public override void SaveSettingsToStorage()