Skip to content

Commit 028db8b

Browse files
SLVS-2525 Introduce base view model for issues to extract common logic.
Make view model for hotspot and taint to extend it.
1 parent f3cf8d6 commit 028db8b

File tree

9 files changed

+102
-20
lines changed

9 files changed

+102
-20
lines changed

src/IssueViz.Security.UnitTests/IssueViz.Security.UnitTests.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,8 @@
2626
<Reference Include="PresentationCore" />
2727
</ItemGroup>
2828

29+
<ItemGroup>
30+
<Folder Include="ReportView\Taints\" />
31+
</ItemGroup>
32+
2933
</Project>

src/IssueViz.Security.UnitTests/ReportView/IssueViewModelTest.cs renamed to src/IssueViz.Security.UnitTests/ReportView/AnalysisIssueViewModelBaseTest.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
namespace SonarLint.VisualStudio.IssueVisualization.Security.UnitTests.ReportView;
2626

2727
[TestClass]
28-
public class IssueViewModelTest
28+
public class AnalysisIssueViewModelBaseTest
2929
{
3030
[TestMethod]
3131
public void Ctor_InitializesPropertiesAsExpected()
@@ -37,7 +37,7 @@ public void Ctor_InitializesPropertiesAsExpected()
3737
"remove todo comment",
3838
"myClass.cs");
3939

40-
var testSubject = new IssueViewModel(analysisIssueVisualization);
40+
var testSubject = new AnalysisIssueViewModelBase(analysisIssueVisualization);
4141

4242
testSubject.Issue.Should().Be(analysisIssueVisualization);
4343
testSubject.RuleInfo.RuleKey.Should().Be(analysisIssueVisualization.RuleId);

src/IssueViz.Security.UnitTests/ReportView/Taint/TaintsReportViewModelTest.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ private static void VerifyExpectedTaintGroupViewModel(GroupFileViewModel groupFi
133133
groupFileVm.FilteredIssues.Should().HaveCount(expectedTaints.Length);
134134
foreach (var expectedTaint in expectedTaints)
135135
{
136-
groupFileVm.FilteredIssues.Should().ContainSingle(vm => ((IssueViewModel)vm).Issue == expectedTaint);
136+
groupFileVm.FilteredIssues.Should().ContainSingle(vm => ((TaintViewModel)vm).Issue == expectedTaint);
137137
}
138138
}
139139
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
using SonarLint.VisualStudio.IssueVisualization.Models;
2+
using SonarLint.VisualStudio.IssueVisualization.Security.ReportView.Taints;
3+
using SonarLint.VisualStudio.IssueVisualization.Security.Taint.Models;
4+
5+
namespace SonarLint.VisualStudio.IssueVisualization.Security.UnitTests.ReportView.Taints;
6+
7+
[TestClass]
8+
public class TaintViewModelTest
9+
{
10+
[TestMethod]
11+
public void Ctor_InitializesPropertiesAsExpected()
12+
{
13+
var analysisIssueVisualization = CreateMockedTaint("csharp:101",
14+
Guid.NewGuid(),
15+
1,
16+
66,
17+
"remove todo comment",
18+
"myClass.cs");
19+
20+
var testSubject = new TaintViewModel(analysisIssueVisualization);
21+
22+
testSubject.TaintIssue.Should().Be(analysisIssueVisualization.Issue);
23+
testSubject.RuleInfo.RuleKey.Should().Be(analysisIssueVisualization.RuleId);
24+
testSubject.RuleInfo.IssueId.Should().Be(analysisIssueVisualization.IssueId);
25+
testSubject.Line.Should().Be(analysisIssueVisualization.Issue.PrimaryLocation.TextRange.StartLine);
26+
testSubject.Column.Should().Be(analysisIssueVisualization.Issue.PrimaryLocation.TextRange.StartLineOffset);
27+
testSubject.Title.Should().Be(analysisIssueVisualization.Issue.PrimaryLocation.Message);
28+
testSubject.FilePath.Should().Be(analysisIssueVisualization.Issue.PrimaryLocation.FilePath);
29+
testSubject.Issue.Should().Be(analysisIssueVisualization);
30+
}
31+
32+
private static IAnalysisIssueVisualization CreateMockedTaint(
33+
string ruleId,
34+
Guid issueId,
35+
int startLine,
36+
int startLineOffset,
37+
string message,
38+
string filePath)
39+
{
40+
var analysisIssueVisualization = Substitute.For<IAnalysisIssueVisualization>();
41+
analysisIssueVisualization.RuleId.Returns(ruleId);
42+
analysisIssueVisualization.IssueId.Returns(issueId);
43+
44+
var analysisIssueBase = Substitute.For<ITaintIssue>();
45+
analysisIssueBase.PrimaryLocation.TextRange.StartLine.Returns(startLine);
46+
analysisIssueBase.PrimaryLocation.TextRange.StartLineOffset.Returns(startLineOffset);
47+
analysisIssueBase.PrimaryLocation.Message.Returns(message);
48+
analysisIssueBase.PrimaryLocation.FilePath.Returns(filePath);
49+
analysisIssueVisualization.Issue.Returns(analysisIssueBase);
50+
51+
return analysisIssueVisualization;
52+
}
53+
}

src/IssueViz.Security/ReportView/IssueViewModel.cs renamed to src/IssueViz.Security/ReportView/AnalysisIssueViewModelBase.cs

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

21+
using SonarLint.VisualStudio.Core.WPF;
2122
using SonarLint.VisualStudio.IssueVisualization.Models;
2223

2324
namespace SonarLint.VisualStudio.IssueVisualization.Security.ReportView;
2425

25-
internal class IssueViewModel : IAnalysisIssueViewModel
26+
internal class AnalysisIssueViewModelBase : ViewModelBase, IAnalysisIssueViewModel
2627
{
27-
public IssueViewModel(IAnalysisIssueVisualization analysisIssueVisualization)
28+
public AnalysisIssueViewModelBase(IAnalysisIssueVisualization analysisIssueVisualization)
2829
{
2930
Issue = analysisIssueVisualization;
3031
RuleInfo = new RuleInfoViewModel(Issue.RuleId, Issue.IssueId);

src/IssueViz.Security/ReportView/Hotspots/HotspotViewModel.cs

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

21-
using SonarLint.VisualStudio.Core.WPF;
22-
using SonarLint.VisualStudio.IssueVisualization.Models;
2321
using SonarLint.VisualStudio.IssueVisualization.Security.Hotspots;
2422

2523
namespace SonarLint.VisualStudio.IssueVisualization.Security.ReportView.Hotspots;
2624

27-
internal class HotspotViewModel : ViewModelBase, IAnalysisIssueViewModel
25+
internal class HotspotViewModel : AnalysisIssueViewModelBase
2826
{
2927
public LocalHotspot LocalHotspot { get; }
3028
public bool ExistsOnServer => LocalHotspot.Visualization.Issue.IssueServerKey != null;
3129

32-
public HotspotViewModel(LocalHotspot localHotspot)
30+
public HotspotViewModel(LocalHotspot localHotspot) : base(localHotspot.Visualization)
3331
{
3432
LocalHotspot = localHotspot;
35-
RuleInfo = new RuleInfoViewModel(localHotspot.Visualization.RuleId, localHotspot.Visualization.IssueId);
3633
}
37-
38-
public int? Line => LocalHotspot.Visualization.Issue.PrimaryLocation.TextRange.StartLine;
39-
public int? Column => LocalHotspot.Visualization.Issue.PrimaryLocation.TextRange.StartLineOffset;
40-
public string Title => LocalHotspot.Visualization.Issue.PrimaryLocation.Message;
41-
public string FilePath => LocalHotspot.Visualization.Issue.PrimaryLocation.FilePath;
42-
public RuleInfoViewModel RuleInfo { get; }
43-
public IAnalysisIssueVisualization Issue => LocalHotspot.Visualization;
4434
}

src/IssueViz.Security/ReportView/ReportViewControl.xaml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
xmlns:vsimagecatalog="clr-namespace:Microsoft.VisualStudio.Imaging;assembly=Microsoft.VisualStudio.ImageCatalog"
1414
xmlns:core="clr-namespace:SonarLint.VisualStudio.Core;assembly=SonarLint.VisualStudio.Core"
1515
xmlns:commands="clr-namespace:SonarLint.VisualStudio.IssueVisualization.IssueVisualizationControl.ViewModels.Commands;assembly=SonarLint.VisualStudio.IssueVisualization"
16+
xmlns:taints="clr-namespace:SonarLint.VisualStudio.IssueVisualization.Security.ReportView.Taints"
1617
DataContext="{Binding RelativeSource={RelativeSource Mode=Self}, Path=ReportViewModel}">
1718
<UserControl.Resources>
1819
<ResourceDictionary>
@@ -424,8 +425,8 @@
424425
</Grid>
425426
</DataTemplate>
426427

427-
<!--Issue styling-->
428-
<DataTemplate DataType="{x:Type reportView:IssueViewModel}">
428+
<!--Taint styling-->
429+
<DataTemplate DataType="{x:Type taints:TaintViewModel}">
429430
<Grid Margin="5,2"
430431
MouseRightButtonDown="TreeViewItem_OnMouseRightButtonDown">
431432
<Grid.ColumnDefinitions>
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
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.IssueVisualization.Models;
22+
using SonarLint.VisualStudio.IssueVisualization.Security.Taint.Models;
23+
24+
namespace SonarLint.VisualStudio.IssueVisualization.Security.ReportView.Taints;
25+
26+
internal class TaintViewModel : AnalysisIssueViewModelBase
27+
{
28+
public ITaintIssue TaintIssue => (ITaintIssue)Issue.Issue;
29+
30+
public TaintViewModel(IAnalysisIssueVisualization analysisIssueVisualization) : base(analysisIssueVisualization)
31+
{
32+
}
33+
}

src/IssueViz.Security/ReportView/Taints/TaintsReportViewModel.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public TaintsReportViewModel(ITaintStore taintsStore)
5252

5353
public ObservableCollection<IGroupViewModel> GetTaintsGroupViewModels()
5454
{
55-
var taints = taintsStore.GetAll().Select(x => new IssueViewModel(x));
55+
var taints = taintsStore.GetAll().Select(x => new TaintViewModel(x));
5656
return GetGroupViewModel(taints);
5757
}
5858

0 commit comments

Comments
 (0)