Skip to content

Commit 13ec57e

Browse files
authored
Merge pull request #379 from tonyhallett/hide-namespace-when-grouping-by-namespace
Hide namespace when grouping by namespace
2 parents 3987815 + 13fc156 commit 13ec57e

File tree

7 files changed

+123
-22
lines changed

7 files changed

+123
-22
lines changed

FineCodeCoverageTests/AppOptionsProvider_Tests.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,7 @@ internal void Should_Use_Deseralized_String_From_Store_For_AppOption_Property(Fu
317317
{ nameof(IAppOptions.ShowToolWindowToolbar),true},
318318
{nameof(IAppOptions.ExcludeAssemblies),new string[]{ "Exclude"} },
319319
{nameof(IAppOptions.IncludeAssemblies),new string[]{ "Include"} },
320+
{nameof(IAppOptions.NamespaceQualification),NamespaceQualification.AlwaysUnqualified }
320321
};
321322
var mockJsonConvertService = autoMocker.GetMock<IJsonConvertService>();
322323
mockJsonConvertService.Setup(

FineCodeCoverageTests/MsCodeCoverage/RunSettingsTemplateReplacementsFactory_Tests.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -701,5 +701,6 @@ internal class TestCoverageProjectOptions : IAppOptions
701701
public string[] ExcludeAssemblies { get; set; }
702702
public string[] IncludeAssemblies { get; set; }
703703
public bool DisabledNoCoverage { get; set; }
704+
public NamespaceQualification NamespaceQualification { get; set; }
704705
}
705706
}

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,8 @@ If you are using option 1) then project and global options will only be used whe
241241
|ToolsDirectory|Folder to which copy tools subfolder. Must alredy exist. Requires restart of VS.|
242242
|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. |
243243
|StickyCoverageTable|Set to true for coverage table to have a sticky thead.|
244-
|NamespacedClasses|Set to false to show classes in report in short form. Affects grouping.|
244+
|NamespacedClasses|Set to false to show types in report in short form. Affects grouping.|
245+
|NamespaceQualification|Control qualification of types in report when NamespacedClasses is true.<br>FullyQualified - always fully qualify.<br>AlwaysUnqualified - always unqualified.<br>UnqualifiedByNamespace - unqualified when grouping by namespace.<br>QualifiedByNamespaceLevel - omits the first grouping level identifier parts. Reduces space whilst maintaining uniqueness.|
245246
|HideFullyCovered|Set to true to hide classes, namespaces and assemblies that are fully covered.|
246247
|Hide0Coverage|Set to true to hide classes, namespaces and assemblies that have 0% coverage.|
247248
|Hide0Coverable|Set to false to show classes, namespaces and assemblies that are not coverable.|

SharedProject/Core/ReportGenerator/ReportGeneratorUtil.cs

Lines changed: 103 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ async Task run(string outputReportType, string inputReports)
170170
reportTypeSettings.Add($@"""-reports:{inputReports}""");
171171
reportTypeSettings.Add($@"""-plugins:{typeof(FccLightReportBuilder).Assembly.Location}""");
172172
reportTypeSettings.Add($@"""-reporttypes:{FccLightReportBuilder.REPORT_TYPE}""");
173-
var (cyclomaticThreshold, crapScoreThreshold, nPathThreshold) = HotspotThresholds();
173+
var (cyclomaticThreshold, crapScoreThreshold, nPathThreshold) = HotspotThresholds(appOptionsProvider.Get());
174174
175175
reportTypeSettings.Add($@"""riskHotspotsAnalysisThresholds:metricThresholdForCyclomaticComplexity={cyclomaticThreshold}""");
176176
reportTypeSettings.Add($@"""riskHotspotsAnalysisThresholds:metricThresholdForCrapScore={crapScoreThreshold}""");
@@ -337,9 +337,9 @@ Alternative is lighten / darken the background color
337337
style.InnerHtml = changedCss;
338338
}
339339
340-
private string GetStickyTableHead()
340+
private string GetStickyTableHead(IAppOptions appOptions)
341341
{
342-
if (!appOptionsProvider.Get().StickyCoverageTable)
342+
if (!appOptions.StickyCoverageTable)
343343
{
344344
return "";
345345
}
@@ -829,9 +829,40 @@ private string HideGroupingCss()
829829
";
830830
}
831831
832-
private string ObserveAndHideFullyCovered()
832+
private string CoverageInfoObserver()
833+
{
834+
var code = @"
835+
var coverageInfoObserver = (function(){
836+
var mutationObserver;
837+
var callbacks = [];
838+
function observe(){
839+
mutationObserver.observe(
840+
document.querySelector(""coverage-info""),
841+
{ attributes: false, childList: true, subtree: true }
842+
)
843+
}
844+
function cb(record,obs){
845+
mutationObserver.disconnect();
846+
for(var i=0;i<callbacks.length;i++){
847+
callbacks[i]();
848+
}
849+
observe();
850+
}
851+
return {
852+
observe:function(callback){
853+
callbacks.push(callback);
854+
if(!mutationObserver){
855+
mutationObserver = new MutationObserver(cb);
856+
observe();
857+
}
858+
}
859+
}
860+
})();
861+
";
862+
return code;
863+
}
864+
private string ObserveAndHideFullyCovered(IAppOptions appOptions)
833865
{
834-
var appOptions = appOptionsProvider.Get();
835866
if (!(appOptions.HideFullyCovered | appOptions.Hide0Coverage | appOptions.Hide0Coverable))
836867
{
837868
return "";
@@ -840,11 +871,9 @@ private string ObserveAndHideFullyCovered()
840871
function getCellValue(row, index){{
841872
return parseInt(row.cells[index].innerText);
842873
}}
843-
var targetNode = document;
844874
845-
var config = {{ attributes: false, childList: true, subtree: true }};
846875
847-
var callback = function(mutationsList, observer) {{
876+
var hideCoverage = function() {{
848877
var rows = document.querySelectorAll(""coverage-info table tbody tr"");
849878
for(var i=0;i<rows.length;i++){{
850879
var row = rows[i];
@@ -878,14 +907,67 @@ function getCellValue(row, index){{
878907
879908
}};
880909
}};
881-
882-
var observer = new MutationObserver(callback);
883-
observer.observe(targetNode, config);
910+
hideCoverage();
911+
coverageInfoObserver.observe(hideCoverage);
884912
";
885913
return code;
886914
}
887915
888-
private string HackGroupingToAllowAll(int groupingLevel)
916+
private string ObserveAndHideNamespaceWhenGroupingByNamespace(IAppOptions appOptions)
917+
{
918+
919+
if (!appOptions.NamespacedClasses || appOptions.NamespaceQualification == NamespaceQualification.FullyQualified)
920+
{
921+
return "";
922+
}
923+
var fullyQualifiedToName = "";
924+
switch(appOptions.NamespaceQualification)
925+
{
926+
case NamespaceQualification.AlwaysUnqualified:
927+
case NamespaceQualification.UnqualifiedByNamespace:
928+
fullyQualifiedToName = "var name = fullyQualified.substring(fullyQualified.lastIndexOf(\".\") + 1);";
929+
break;
930+
case NamespaceQualification.QualifiedByNamespaceLevel:
931+
fullyQualifiedToName = @"
932+
var parts = fullyQualified.split(""."");
933+
var namespaceParts = parts.slice(0,parts.length-1);
934+
var type = parts[parts.length-1];
935+
var name = type;
936+
if(namespaceParts.length > groupingLevel){
937+
name = namespaceParts.slice(groupingLevel).join(""."") + ""."" + type;
938+
}";
939+
break;
940+
default:
941+
throw new Exception($"Unknown GroupingNamespaceQualification '{appOptions.NamespaceQualification}'");
942+
}
943+
var alwaysUnqualified = appOptions.NamespaceQualification == NamespaceQualification.AlwaysUnqualified;
944+
var code = $@"
945+
var config = {{ attributes: false, childList: true, subtree: true }};
946+
947+
var changeQualification = function() {{
948+
var groupingInput = document.querySelector(""coverage-info .customizebox input"");
949+
if(!groupingInput || groupingInput.value <= 0 && !{alwaysUnqualified.ToString().ToLower()}){{
950+
return;
951+
}}
952+
953+
var groupingLevel = groupingInput.value;
954+
var rows = document.querySelectorAll(""coverage-info table tbody tr[class-row]"");
955+
for(var i=0;i<rows.length;i++){{
956+
var row = rows[i];
957+
var cell = row.cells[0];
958+
var a = cell.querySelector(""a"");
959+
var fullyQualified = a.innerText;
960+
{fullyQualifiedToName}
961+
a.innerText = name;
962+
}};
963+
}};
964+
changeQualification();
965+
coverageInfoObserver.observe(changeQualification);
966+
";
967+
return code;
968+
}
969+
970+
private string HackGroupingToAllowAll(int groupingLevel)
889971
{
890972
return $@"
891973
var customizeBox = document.getElementsByClassName('customizebox')[0];
@@ -969,7 +1051,7 @@ public string ProcessUnifiedHtml(string htmlForProcessing, string reportOutputFo
9691051
ReportColours = reportColoursProvider.GetColours();
9701052
return assemblyUtil.RunInAssemblyResolvingContext(() =>
9711053
{
972-
var (cyclomaticThreshold, crapScoreThreshold, nPathThreshold) = HotspotThresholds();
1054+
var (cyclomaticThreshold, crapScoreThreshold, nPathThreshold) = HotspotThresholds(appOptions);
9731055
var noRiskHotspotsHeader = "No risk hotspots that exceed options :";
9741056
var noRiskHotspotsCyclomaticMsg = $"Cyclomatic complexity : {cyclomaticThreshold}";
9751057
var noRiskHotspotsNpathMsg =$"NPath complexity : {nPathThreshold}";
@@ -1123,9 +1205,11 @@ public string ProcessUnifiedHtml(string htmlForProcessing, string reportOutputFo
11231205
11241206
htmlSb.Replace("</body>", $@"
11251207
<script type=""text/javascript"">
1126-
{GetStickyTableHead()}
1208+
{GetStickyTableHead(appOptions)}
11271209
{HackGroupingToAllowAll(groupingLevel)}
1128-
{ObserveAndHideFullyCovered()}
1210+
{CoverageInfoObserver()}
1211+
{ObserveAndHideNamespaceWhenGroupingByNamespace(appOptions)}
1212+
{ObserveAndHideFullyCovered(appOptions)}
11291213
function getRuleBySelector(cssRules,selector){{
11301214
for(var i=0;i<cssRules.length;i++){{
11311215
if(cssRules[i].selectorText == selector){{
@@ -1640,13 +1724,12 @@ private void HideRowsFromOverviewTable(HtmlDocument doc)
16401724
}
16411725
}
16421726

1643-
private (int cyclomaticThreshold, int crapScoreThreshold, int nPathThreshold) HotspotThresholds()
1727+
private (int cyclomaticThreshold, int crapScoreThreshold, int nPathThreshold) HotspotThresholds(IAppOptions appOptions)
16441728
{
1645-
var options = appOptionsProvider.Get();
16461729
return (
1647-
options.ThresholdForCyclomaticComplexity,
1648-
options.ThresholdForCrapScore,
1649-
options.ThresholdForNPathComplexity
1730+
appOptions.ThresholdForCyclomaticComplexity,
1731+
appOptions.ThresholdForCrapScore,
1732+
appOptions.ThresholdForNPathComplexity
16501733
);
16511734

16521735
}

SharedProject/Options/AppOptionsPage.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,9 +263,13 @@ You can also ignore additional attributes by adding to this list (short name or
263263
public bool StickyCoverageTable { get; set; }
264264

265265
[Category(commonReportCategory)]
266-
[Description("Set to false to show classes in report in short form.")]
266+
[Description("Set to false to show types in report in short form.")]
267267
public bool NamespacedClasses { get; set; }
268268

269+
[Category(commonReportCategory)]
270+
[Description("Control qualification of types when NamespacedClasses is true.")]
271+
public NamespaceQualification NamespaceQualification { get; set; }
272+
269273
[Category(commonReportCategory)]
270274
[Description("Set to true to hide classes, namespaces and assemblies that are fully covered.")]
271275
public bool HideFullyCovered { get; set; }

SharedProject/Options/AppOptionsProvider.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,5 +209,6 @@ internal class AppOptions : IAppOptions
209209
public bool ShowToolWindowToolbar { get; set; }
210210
public string[] ExcludeAssemblies { get; set; }
211211
public string[] IncludeAssemblies { get; set; }
212+
public NamespaceQualification NamespaceQualification { get; set; }
212213
}
213214
}

SharedProject/Options/IAppOptions.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,5 +65,15 @@ internal interface IAppOptions : IMsCodeCoverageOptions, IOpenCoverCoverletExclu
6565
bool AdjacentBuildOutput { get; set; }
6666
RunMsCodeCoverage RunMsCodeCoverage { get; set; }
6767
bool ShowToolWindowToolbar { get; set; }
68+
69+
NamespaceQualification NamespaceQualification { get; set; }
70+
}
71+
72+
internal enum NamespaceQualification
73+
{
74+
FullyQualified,
75+
AlwaysUnqualified,
76+
UnqualifiedByNamespace,
77+
QualifiedByNamespaceLevel
6878
}
6979
}

0 commit comments

Comments
 (0)