Skip to content

Commit 2e97d54

Browse files
SLVS-2525 Show taints in report view (#6426)
1 parent 157f324 commit 2e97d54

21 files changed

+1089
-84
lines changed

src/IssueViz.Security.UnitTests/Hotspots/LocalHotspotTests.cs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
1919
*/
2020

21+
using SonarLint.VisualStudio.Core.Analysis;
22+
using SonarLint.VisualStudio.IssueVisualization.Models;
2123
using SonarLint.VisualStudio.IssueVisualization.Security.Hotspots;
2224

2325
namespace SonarLint.VisualStudio.IssueVisualization.Security.UnitTests.Hotspots;
@@ -32,4 +34,55 @@ public void Ctor_VisualizationIsNull_Throws()
3234

3335
test.Should().Throw<ArgumentNullException>().WithMessage("*visualization*");
3436
}
37+
38+
[TestMethod]
39+
[DataRow(HotspotStatus.ToReview)]
40+
[DataRow(HotspotStatus.Acknowledged)]
41+
[DataRow(HotspotStatus.Fixed)]
42+
[DataRow(HotspotStatus.Safe)]
43+
public void ToLocalHotspot_WithHotspotStatus_CreatesLocalHotspot(HotspotStatus hotspotStatus)
44+
{
45+
var analysisIssueVisualization = CreateMockedHotspot(hotspotStatus);
46+
47+
var result = LocalHotspot.ToLocalHotspot(analysisIssueVisualization);
48+
49+
result.Visualization.Should().Be(analysisIssueVisualization);
50+
result.HotspotStatus.Should().Be(hotspotStatus);
51+
}
52+
53+
[TestMethod]
54+
[DataRow(HotspotPriority.High)]
55+
[DataRow(HotspotPriority.Low)]
56+
[DataRow(HotspotPriority.Medium)]
57+
public void ToLocalHotspot_WithHotspotPriority_CreatesLocalHotspot(HotspotPriority hotspotPriority)
58+
{
59+
var analysisIssueVisualization = CreateMockedHotspot(hotspotStatus: default, hotspotPriority);
60+
61+
var result = LocalHotspot.ToLocalHotspot(analysisIssueVisualization);
62+
63+
result.Visualization.Should().Be(analysisIssueVisualization);
64+
result.Priority.Should().Be(hotspotPriority);
65+
}
66+
67+
[TestMethod]
68+
public void ToLocalHotspot_NoHotspotPriority_ReturnsHighPriority()
69+
{
70+
var analysisIssueVisualization = CreateMockedHotspot(hotspotStatus: default, hotspotPriority: null);
71+
72+
var result = LocalHotspot.ToLocalHotspot(analysisIssueVisualization);
73+
74+
result.Visualization.Should().Be(analysisIssueVisualization);
75+
result.Priority.Should().Be(HotspotPriority.High);
76+
}
77+
78+
private IAnalysisIssueVisualization CreateMockedHotspot(HotspotStatus hotspotStatus, HotspotPriority? hotspotPriority = null)
79+
{
80+
var analysisIssueVisualization = Substitute.For<IAnalysisIssueVisualization>();
81+
var analysisHotspotIssue = Substitute.For<IAnalysisHotspotIssue>();
82+
analysisHotspotIssue.HotspotStatus.Returns(hotspotStatus);
83+
analysisHotspotIssue.HotspotPriority.Returns(hotspotPriority);
84+
analysisIssueVisualization.Issue.Returns(analysisHotspotIssue);
85+
86+
return analysisIssueVisualization;
87+
}
3588
}
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
/*
2+
* SonarLint for Visual Studio
3+
* Copyright (C) 2016-2025 SonarSource SA
4+
* mailto:info AT sonarsource DOT com
5+
*
6+
* This program is free software; you can redistribute it and/or
7+
* modify it under the terms of the GNU Lesser General Public
8+
* License as published by the Free Software Foundation; either
9+
* version 3 of the License, or (at your option) any later version.
10+
*
11+
* This program is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14+
* Lesser General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU Lesser General Public License
17+
* along with this program; if not, write to the Free Software Foundation,
18+
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19+
*/
20+
21+
using SonarLint.VisualStudio.Core.Analysis;
22+
using SonarLint.VisualStudio.IssueVisualization.Models;
23+
using SonarLint.VisualStudio.IssueVisualization.Security.ReportView;
24+
25+
namespace SonarLint.VisualStudio.IssueVisualization.Security.UnitTests.ReportView;
26+
27+
[TestClass]
28+
public class AnalysisIssueViewModelBaseTest
29+
{
30+
[TestMethod]
31+
public void Ctor_InitializesPropertiesAsExpected()
32+
{
33+
var analysisIssueVisualization = CreateMockedIssue("csharp:101",
34+
Guid.NewGuid(),
35+
1,
36+
66,
37+
"remove todo comment",
38+
"myClass.cs");
39+
40+
var testSubject = new AnalysisIssueViewModelBase(analysisIssueVisualization);
41+
42+
testSubject.Issue.Should().Be(analysisIssueVisualization);
43+
testSubject.RuleInfo.RuleKey.Should().Be(analysisIssueVisualization.RuleId);
44+
testSubject.RuleInfo.IssueId.Should().Be(analysisIssueVisualization.IssueId);
45+
testSubject.Line.Should().Be(analysisIssueVisualization.Issue.PrimaryLocation.TextRange.StartLine);
46+
testSubject.Column.Should().Be(analysisIssueVisualization.Issue.PrimaryLocation.TextRange.StartLineOffset);
47+
testSubject.Title.Should().Be(analysisIssueVisualization.Issue.PrimaryLocation.Message);
48+
testSubject.FilePath.Should().Be(analysisIssueVisualization.Issue.PrimaryLocation.FilePath);
49+
testSubject.Issue.Should().Be(analysisIssueVisualization);
50+
}
51+
52+
[TestMethod]
53+
[DataRow("931CF6A0-A479-4566-929B-FC6D3AB3D3EA", "serverKey")]
54+
[DataRow(null, "serverKey")]
55+
[DataRow(null, null)]
56+
public void IsSameAnalysisIssue_SameIdAndServerKey_ReturnsTrue(string issueId, string serverKey)
57+
{
58+
var analysisIssueVisualization1 = CreateMockedIssue(GetGuid(issueId), serverKey);
59+
var analysisIssueVisualization2 = CreateMockedIssue(analysisIssueVisualization1.Issue.Id, analysisIssueVisualization1.Issue.IssueServerKey);
60+
61+
new AnalysisIssueViewModelBase(analysisIssueVisualization1).IsSameAnalysisIssue(analysisIssueVisualization2).Should().BeTrue();
62+
}
63+
64+
[TestMethod]
65+
public void IsSameAnalysisIssue_SameReference_ReturnsTrue()
66+
{
67+
var analysisIssueVisualization1 = CreateMockedIssue(Guid.NewGuid(), "E2670BAB-4B1E-49C2-8641-7B77CE2A6DBF");
68+
69+
new AnalysisIssueViewModelBase(analysisIssueVisualization1).IsSameAnalysisIssue(analysisIssueVisualization1).Should().BeTrue();
70+
}
71+
72+
[TestMethod]
73+
[DataRow("931CF6A0-A479-4566-929B-FC6D3AB3D3EA", "E2670BAB-4B1E-49C2-8641-7B77CE2A6DBF")]
74+
[DataRow(null, "931CF6A0-A479-4566-929B-FC6D3AB3D3EA")]
75+
public void IsSameAnalysisIssue_DifferentId_ReturnsFalse(string issueId1, string issueId2)
76+
{
77+
var serverKey = Guid.NewGuid().ToString();
78+
var analysisIssueVisualization1 = CreateMockedIssue(GetGuid(issueId1), serverKey);
79+
var analysisIssueVisualization2 = CreateMockedIssue(GetGuid(issueId2), serverKey);
80+
81+
new AnalysisIssueViewModelBase(analysisIssueVisualization1).IsSameAnalysisIssue(analysisIssueVisualization2).Should().BeFalse();
82+
}
83+
84+
[TestMethod]
85+
[DataRow("931CF6A0-A479-4566-929B-FC6D3AB3D3EA", "E2670BAB-4B1E-49C2-8641-7B77CE2A6DBF")]
86+
[DataRow(null, "931CF6A0-A479-4566-929B-FC6D3AB3D3EA")]
87+
public void IsSameAnalysisIssue_DifferentServerKey_ReturnsFalse(string serverKey1, string serverKey2)
88+
{
89+
var issueId = Guid.NewGuid();
90+
var analysisIssueVisualization1 = CreateMockedIssue(issueId, serverKey1);
91+
var analysisIssueVisualization2 = CreateMockedIssue(issueId, serverKey2);
92+
93+
new AnalysisIssueViewModelBase(analysisIssueVisualization1).IsSameAnalysisIssue(analysisIssueVisualization2).Should().BeFalse();
94+
}
95+
96+
private static IAnalysisIssueVisualization CreateMockedIssue(
97+
string ruleId,
98+
Guid issueId,
99+
int startLine,
100+
int startLineOffset,
101+
string message,
102+
string filePath)
103+
{
104+
var analysisIssueVisualization = Substitute.For<IAnalysisIssueVisualization>();
105+
analysisIssueVisualization.RuleId.Returns(ruleId);
106+
analysisIssueVisualization.IssueId.Returns(issueId);
107+
108+
var analysisIssueBase = Substitute.For<IAnalysisIssueBase>();
109+
analysisIssueBase.PrimaryLocation.TextRange.StartLine.Returns(startLine);
110+
analysisIssueBase.PrimaryLocation.TextRange.StartLineOffset.Returns(startLineOffset);
111+
analysisIssueBase.PrimaryLocation.Message.Returns(message);
112+
analysisIssueBase.PrimaryLocation.FilePath.Returns(filePath);
113+
analysisIssueVisualization.Issue.Returns(analysisIssueBase);
114+
115+
return analysisIssueVisualization;
116+
}
117+
118+
private static IAnalysisIssueVisualization CreateMockedIssue(
119+
Guid? issueId,
120+
string serverKey)
121+
{
122+
var analysisIssueVisualization = Substitute.For<IAnalysisIssueVisualization>();
123+
var analysisIssueBase = Substitute.For<IAnalysisIssueBase>();
124+
analysisIssueBase.IssueServerKey.Returns(serverKey);
125+
analysisIssueBase.Id.Returns(issueId);
126+
analysisIssueVisualization.Issue.Returns(analysisIssueBase);
127+
128+
return analysisIssueVisualization;
129+
}
130+
131+
private static Guid? GetGuid(string issueId) => issueId == null ? null : Guid.Parse(issueId);
132+
}

src/IssueViz.Security.UnitTests/ReportView/GroupFileViewModelTest.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,26 @@
1919
*/
2020

2121
using System.Collections.ObjectModel;
22+
using SonarLint.VisualStudio.Core;
2223
using SonarLint.VisualStudio.IssueVisualization.Security.ReportView;
2324

2425
namespace SonarLint.VisualStudio.IssueVisualization.Security.UnitTests.ReportView;
2526

2627
[TestClass]
2728
public class GroupFileViewModelTest
2829
{
30+
private IThreadHandling threadHandling;
31+
32+
[TestInitialize]
33+
public void TestInitialize() => threadHandling = Substitute.For<IThreadHandling>();
34+
2935
[TestMethod]
3036
public void Ctor_InitializesPropertiesAsExpected()
3137
{
3238
var issues = new ObservableCollection<IIssueViewModel> { Substitute.For<IIssueViewModel>() };
3339
var filePath = "c:\\myDir\\myFile.cs";
3440

35-
var testSubject = new GroupFileViewModel(filePath, issues);
41+
var testSubject = new GroupFileViewModel(filePath, issues, threadHandling);
3642

3743
testSubject.Title.Should().Be("myFile.cs");
3844
testSubject.FilePath.Should().Be(filePath);

src/IssueViz.Security.UnitTests/ReportView/Hotspots/HotspotsReportViewModelTest.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ public class HotspotsReportViewModelTest
4242
private IReviewHotspotsService reviewHotspotsService;
4343
private ITelemetryManager telemetryManager;
4444
private HotspotsReportViewModel testSubject;
45+
private IThreadHandling threadHandling;
4546

4647
[TestInitialize]
4748
public void TestInitialize()
@@ -50,7 +51,8 @@ public void TestInitialize()
5051
reviewHotspotsService = Substitute.For<IReviewHotspotsService>();
5152
messageBox = Substitute.For<IMessageBox>();
5253
telemetryManager = Substitute.For<ITelemetryManager>();
53-
testSubject = new HotspotsReportViewModel(localHotspotsStore, reviewHotspotsService, messageBox, telemetryManager);
54+
threadHandling = Substitute.For<IThreadHandling>();
55+
testSubject = new HotspotsReportViewModel(localHotspotsStore, reviewHotspotsService, messageBox, telemetryManager, threadHandling);
5456
}
5557

5658
[TestMethod]
@@ -59,7 +61,8 @@ public void MefCtor_CheckIsExported() =>
5961
MefTestHelpers.CreateExport<ILocalHotspotsStore>(),
6062
MefTestHelpers.CreateExport<IReviewHotspotsService>(),
6163
MefTestHelpers.CreateExport<IMessageBox>(),
62-
MefTestHelpers.CreateExport<ITelemetryManager>()
64+
MefTestHelpers.CreateExport<ITelemetryManager>(),
65+
MefTestHelpers.CreateExport<IThreadHandling>()
6366
);
6467

6568
[TestMethod]
@@ -123,7 +126,7 @@ public void GetHotspotsGroupViewModels_TwoHotspotsInDifferentFiles_CreatesTwoGro
123126
public void HotspotsChanged_RaisedOnStoreIssuesChanged()
124127
{
125128
var raised = false;
126-
testSubject.HotspotsChanged += (_, _) => raised = true;
129+
testSubject.IssuesChanged += (_, _) => raised = true;
127130

128131
localHotspotsStore.IssuesChanged += Raise.Event<EventHandler<IssuesChangedEventArgs>>(null, null);
129132

0 commit comments

Comments
 (0)