diff --git a/src/Core/IFolderWorkspaceMonitor.cs b/src/Core/IFolderWorkspaceMonitor.cs
index ce5a2f8a94..080f08d883 100644
--- a/src/Core/IFolderWorkspaceMonitor.cs
+++ b/src/Core/IFolderWorkspaceMonitor.cs
@@ -34,6 +34,6 @@ public interface IFolderWorkspaceMonitor
/// We need this event since certain parts of our code, i.e. ,
/// rely on VsHierarchy being initialized by the time they're called.
///
- event EventHandler FolderWorkspaceInitialized;
+ event EventHandler FolderWorkspaceInitialized; // todo
}
}
diff --git a/src/IssueViz.Security.UnitTests/Taint/TaintIssuesBindingMonitorTests.cs b/src/IssueViz.Security.UnitTests/Taint/TaintIssuesBindingMonitorTests.cs
deleted file mode 100644
index aed1f4acc5..0000000000
--- a/src/IssueViz.Security.UnitTests/Taint/TaintIssuesBindingMonitorTests.cs
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * SonarLint for Visual Studio
- * Copyright (C) 2016-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-using System;
-using FluentAssertions;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using Moq;
-using SonarLint.VisualStudio.Core;
-using SonarLint.VisualStudio.Core.Binding;
-using SonarLint.VisualStudio.TestInfrastructure;
-using SonarLint.VisualStudio.IssueVisualization.Security.Taint;
-
-namespace SonarLint.VisualStudio.IssueVisualization.Security.UnitTests.Taint
-{
- [TestClass]
- public class TaintIssuesBindingMonitorTests
- {
- [TestMethod]
- public void MefCtor_CheckIsExported()
- {
- MefTestHelpers.CheckTypeCanBeImported(
- MefTestHelpers.CreateExport(),
- MefTestHelpers.CreateExport(),
- MefTestHelpers.CreateExport());
- }
-
- [TestMethod]
- public void Ctor_SubscribeToSolutionBindingUpdated()
- {
- var synchronizer = new Mock();
- var activeSolutionBoundTracker = new Mock();
- var folderWorkspaceInitialized = new Mock();
-
- new TaintIssuesBindingMonitor(activeSolutionBoundTracker.Object, folderWorkspaceInitialized.Object, synchronizer.Object);
- synchronizer.Invocations.Clear();
-
- activeSolutionBoundTracker.Raise(x=> x.SolutionBindingUpdated += null, EventArgs.Empty);
-
- synchronizer.Verify(x=> x.SynchronizeWithServer(), Times.Once);
- }
-
- [TestMethod]
- public void Ctor_SubscribeToSolutionBindingChanged()
- {
- var synchronizer = new Mock();
- var activeSolutionBoundTracker = new Mock();
- var folderWorkspaceInitialized = new Mock();
-
- new TaintIssuesBindingMonitor(activeSolutionBoundTracker.Object, folderWorkspaceInitialized.Object, synchronizer.Object);
- synchronizer.Invocations.Clear();
-
- activeSolutionBoundTracker.Raise(x => x.SolutionBindingChanged += null, new ActiveSolutionBindingEventArgs(BindingConfiguration.Standalone));
-
- synchronizer.Verify(x => x.SynchronizeWithServer(), Times.Once);
- }
-
- [TestMethod]
- public void Ctor_SubscribeToFolderInitialized()
- {
- var synchronizer = new Mock();
- var activeSolutionBoundTracker = new Mock();
- var folderWorkspaceInitialized = new Mock();
-
- new TaintIssuesBindingMonitor(activeSolutionBoundTracker.Object, folderWorkspaceInitialized.Object, synchronizer.Object);
- synchronizer.Invocations.Clear();
-
- folderWorkspaceInitialized.Raise(x => x.FolderWorkspaceInitialized += null, EventArgs.Empty);
-
- synchronizer.Verify(x => x.SynchronizeWithServer(), Times.Once);
- }
-
- [TestMethod]
- public void Dispose_UnsubscribeFromEvents()
- {
- var synchronizer = new Mock();
- var activeSolutionBoundTracker = new Mock();
- var folderWorkspaceInitialized = new Mock();
-
- var testSubject = new TaintIssuesBindingMonitor(activeSolutionBoundTracker.Object, folderWorkspaceInitialized.Object, synchronizer.Object);
- testSubject.Dispose();
- synchronizer.Invocations.Clear();
-
- folderWorkspaceInitialized.Raise(x => x.FolderWorkspaceInitialized += null, EventArgs.Empty);
- activeSolutionBoundTracker.Raise(x => x.SolutionBindingUpdated += null, EventArgs.Empty);
- activeSolutionBoundTracker.Raise(x => x.SolutionBindingChanged += null, new ActiveSolutionBindingEventArgs(BindingConfiguration.Standalone));
-
- synchronizer.Invocations.Count.Should().Be(0);
- }
- }
-}
diff --git a/src/IssueViz.Security.UnitTests/Taint/TaintIssuesConfigurationScopeMonitorTests.cs b/src/IssueViz.Security.UnitTests/Taint/TaintIssuesConfigurationScopeMonitorTests.cs
new file mode 100644
index 0000000000..32d6c8c56f
--- /dev/null
+++ b/src/IssueViz.Security.UnitTests/Taint/TaintIssuesConfigurationScopeMonitorTests.cs
@@ -0,0 +1,63 @@
+/*
+ * SonarLint for Visual Studio
+ * Copyright (C) 2016-2024 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+using SonarLint.VisualStudio.IssueVisualization.Security.Taint;
+using SonarLint.VisualStudio.SLCore.State;
+
+namespace SonarLint.VisualStudio.IssueVisualization.Security.UnitTests.Taint;
+
+[TestClass]
+public class TaintIssuesConfigurationScopeMonitorTests
+{
+ [TestMethod]
+ public void Ctor_SubscribesToConfigurationScopeEvents()
+ {
+ var activeConfigScopeTracker = Substitute.For();
+
+ _ = new TaintIssuesConfigurationScopeMonitor(activeConfigScopeTracker, Substitute.For());
+
+ activeConfigScopeTracker.Received().CurrentConfigurationScopeChanged += Arg.Any();
+ }
+
+ [TestMethod]
+ public void Dispose_UnsubscribesToConfigurationScopeEvents()
+ {
+ var activeConfigScopeTracker = Substitute.For();
+ var testSubject = new TaintIssuesConfigurationScopeMonitor(activeConfigScopeTracker, Substitute.For());
+
+ testSubject.Dispose();
+
+ activeConfigScopeTracker.Received().CurrentConfigurationScopeChanged -= Arg.Any();
+ }
+
+ [TestMethod]
+ public void ConfigScopeChangedEvent_CallsTaintSynchronizer()
+ {
+ var activeConfigScopeTracker = Substitute.For();
+ var configurationScope = new ConfigurationScope("config scope");
+ activeConfigScopeTracker.Current.Returns(configurationScope);
+ var taintIssuesSynchronizer = Substitute.For();
+ _ = new TaintIssuesConfigurationScopeMonitor(activeConfigScopeTracker, taintIssuesSynchronizer);
+
+ activeConfigScopeTracker.CurrentConfigurationScopeChanged += Raise.Event();
+
+ taintIssuesSynchronizer.Received(1).UpdateTaintVulnerabilitiesAsync(configurationScope);
+ }
+}
diff --git a/src/IssueViz.Security.UnitTests/Taint/TaintList/TaintIssuesControlViewModelTests.cs b/src/IssueViz.Security.UnitTests/Taint/TaintList/TaintIssuesControlViewModelTests.cs
index 95e90b3330..a32de3b9aa 100644
--- a/src/IssueViz.Security.UnitTests/Taint/TaintList/TaintIssuesControlViewModelTests.cs
+++ b/src/IssueViz.Security.UnitTests/Taint/TaintList/TaintIssuesControlViewModelTests.cs
@@ -1,4 +1,4 @@
-/*
+/*
* SonarLint for Visual Studio
* Copyright (C) 2016-2024 SonarSource SA
* mailto:info AT sonarsource DOT com
@@ -694,48 +694,6 @@ public void SetSelectedIssue_ValueIsTheSame_SelectionServiceNotCalled()
selectionService.VerifyNoOtherCalls();
}
- [TestMethod]
- public void AnalysisInformation_NoAnalysisInformation_Null()
- {
- var store = new Mock();
- SetupAnalysisInformation(store, null);
-
- var testSubject = CreateTestSubject(store: store);
-
- testSubject.AnalysisInformation.Should().BeNull();
- }
-
- [TestMethod]
- public void AnalysisInformation_HasAnalysisInformation_PropertySet()
- {
- var store = new Mock();
- var analysisInformation = new AnalysisInformation("some branch", default);
- SetupAnalysisInformation(store, analysisInformation);
-
- var testSubject = CreateTestSubject(store: store);
-
- testSubject.AnalysisInformation.Should().BeSameAs(analysisInformation);
- }
-
- [TestMethod]
- public void AnalysisInformation_IssuesChanged_RaisesPropertyChanged()
- {
- var store = new Mock();
- var testSubject = CreateTestSubject(store: store);
-
- var eventHandler = new Mock();
- testSubject.PropertyChanged += eventHandler.Object;
-
- var analysisInformation = new AnalysisInformation("some branch", default);
-
- SetupAnalysisInformation(store, analysisInformation);
- RaiseStoreIssuesChangedEvent(store);
-
- VerifyPropertyChangedWasRaised(eventHandler, nameof(testSubject.AnalysisInformation));
-
- testSubject.AnalysisInformation.Should().BeSameAs(analysisInformation);
- }
-
[TestMethod]
[DataRow(null, ServerType.SonarCloud, nameof(ServerType.SonarCloud), true)]
[DataRow(null, null, "", false)]
@@ -1011,10 +969,5 @@ private void VerifyPropertyChangedWasRaised(Mock ev
It.Is((PropertyChangedEventArgs e) => e.PropertyName == expectedProperty)),
Times.Once);
}
-
- private void SetupAnalysisInformation(Mock store, AnalysisInformation analysisInformation)
- {
- store.Setup(x => x.GetAnalysisInformation()).Returns(analysisInformation);
- }
}
}
diff --git a/src/IssueViz.Security.UnitTests/Taint/TaintStoreTests.cs b/src/IssueViz.Security.UnitTests/Taint/TaintStoreTests.cs
index 167bc740ca..585b5953d2 100644
--- a/src/IssueViz.Security.UnitTests/Taint/TaintStoreTests.cs
+++ b/src/IssueViz.Security.UnitTests/Taint/TaintStoreTests.cs
@@ -1,391 +1,391 @@
-/*
- * SonarLint for Visual Studio
- * Copyright (C) 2016-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-using System;
-using System.ComponentModel.Composition;
-using System.ComponentModel.Composition.Hosting;
-using System.Linq;
-using FluentAssertions;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using Moq;
-using SonarLint.VisualStudio.TestInfrastructure;
-using SonarLint.VisualStudio.IssueVisualization.Models;
-using SonarLint.VisualStudio.IssueVisualization.Security.IssuesStore;
-using SonarLint.VisualStudio.IssueVisualization.Security.Taint;
-using SonarLint.VisualStudio.IssueVisualization.Security.Taint.Models;
-
-namespace SonarLint.VisualStudio.IssueVisualization.Security.UnitTests.Taint
-{
- [TestClass]
- public class TaintStoreTests
- {
- [TestMethod]
- public void MefCtor_CheckExports()
- {
- var batch = new CompositionBatch();
-
- var storeImport = new SingleObjectImporter();
- var issuesStoreImport = new SingleObjectImporter();
- batch.AddPart(storeImport);
- batch.AddPart(issuesStoreImport);
-
- var catalog = new TypeCatalog(typeof(TaintStore));
- using var container = new CompositionContainer(catalog);
- container.Compose(batch);
-
- storeImport.Import.Should().NotBeNull();
- issuesStoreImport.Import.Should().NotBeNull();
-
- storeImport.Import.Should().BeSameAs(issuesStoreImport.Import);
- }
-
- [TestMethod]
- public void GetAll_ReturnsImmutableInstance()
- {
- var testSubject = CreateTestSubject();
- var oldItems = new[] { SetupIssueViz(), SetupIssueViz() };
- testSubject.Set(oldItems, new AnalysisInformation("some branch", DateTimeOffset.Now));
-
- var issuesList1 = testSubject.GetAll();
- testSubject.Add(SetupIssueViz());
- var issuesList2 = testSubject.GetAll();
-
- issuesList1.Count.Should().Be(2);
- issuesList2.Count.Should().Be(3);
- }
-
- [TestMethod]
- public void Set_NullCollection_ArgumentNullException()
- {
- var testSubject = CreateTestSubject();
-
- Action act = () => testSubject.Set(null, null);
-
- act.Should().Throw().And.ParamName.Should().Be("issueVisualizations");
- }
-
- [TestMethod]
- public void Set_NoSubscribersToIssuesChangedEvent_NoException()
- {
- var testSubject = CreateTestSubject();
-
- Action act = () => testSubject.Set(new[] { SetupIssueViz() }, null);
-
- act.Should().NotThrow();
- }
-
- [TestMethod]
- public void Set_NoPreviousItems_NoNewItems_CollectionChangedAndEventRaised()
- {
- var testSubject = CreateTestSubject();
-
- var callCount = 0;
- testSubject.IssuesChanged += (sender, args) => { callCount++; };
-
- testSubject.Set(Enumerable.Empty(), null);
-
- testSubject.GetAll().Should().BeEmpty();
- callCount.Should().Be(1);
- }
-
- [TestMethod]
- public void Set_NoPreviousItems_HasNewItems_CollectionChangedAndEventRaised()
- {
- var testSubject = CreateTestSubject();
-
- var callCount = 0;
- IssuesChangedEventArgs suppliedArgs = null;
- testSubject.IssuesChanged += (sender, args) => { callCount++; suppliedArgs = args; };
-
- var newItems = new[] { SetupIssueViz(), SetupIssueViz() };
- testSubject.Set(newItems, null);
-
- testSubject.GetAll().Should().BeEquivalentTo(newItems);
- callCount.Should().Be(1);
- suppliedArgs.RemovedIssues.Should().BeEmpty();
- suppliedArgs.AddedIssues.Should().BeEquivalentTo(newItems);
- }
-
- [TestMethod]
- public void Set_HasPreviousItems_NoNewItems_CollectionChangedAndEventRaised()
- {
- var testSubject = CreateTestSubject();
-
- var oldItems = new[] { SetupIssueViz(), SetupIssueViz() };
- testSubject.Set(oldItems, null);
-
- var callCount = 0;
- IssuesChangedEventArgs suppliedArgs = null;
- testSubject.IssuesChanged += (sender, args) => { callCount++; suppliedArgs = args; };
-
- testSubject.Set(Enumerable.Empty(), null);
-
- testSubject.GetAll().Should().BeEmpty();
- callCount.Should().Be(1);
- suppliedArgs.RemovedIssues.Should().BeEquivalentTo(oldItems);
- suppliedArgs.AddedIssues.Should().BeEmpty();
- }
-
- [TestMethod]
- public void Set_HasPreviousItems_HasNewItems_CollectionChangedAndEventRaised()
- {
- var testSubject = CreateTestSubject();
-
- var oldItems = new[] { SetupIssueViz(), SetupIssueViz() };
- testSubject.Set(oldItems, null);
-
- var callCount = 0;
- IssuesChangedEventArgs suppliedArgs = null;
- testSubject.IssuesChanged += (sender, args) => { callCount++; suppliedArgs = args; };
-
- var newItems = new[] { SetupIssueViz(), SetupIssueViz() };
- testSubject.Set(newItems, null);
-
- testSubject.GetAll().Should().BeEquivalentTo(newItems);
- callCount.Should().Be(1);
- suppliedArgs.RemovedIssues.Should().BeEquivalentTo(oldItems);
- suppliedArgs.AddedIssues.Should().BeEquivalentTo(newItems);
- }
-
- [TestMethod]
- public void Set_HasPreviousItems_HasSomeNewItems_CollectionChangedAndEventRaised()
- {
- var testSubject = CreateTestSubject();
-
- var issueViz1 = SetupIssueViz("key1");
- var issueViz2 = SetupIssueViz("key2");
- var issueViz2NewObject = SetupIssueViz("key2");
- var issueViz3 = SetupIssueViz("key3");
-
- var oldItems = new[] { issueViz1, issueViz2 };
- testSubject.Set(oldItems, null);
-
- var callCount = 0;
- IssuesChangedEventArgs suppliedArgs = null;
- testSubject.IssuesChanged += (sender, args) => { callCount++; suppliedArgs = args; };
-
- var newItems = new[] { issueViz2NewObject, issueViz3};
- testSubject.Set(newItems, null);
-
- testSubject.GetAll().Should().BeEquivalentTo(newItems);
- callCount.Should().Be(1);
- suppliedArgs.RemovedIssues.Should().BeEquivalentTo(issueViz1);
- suppliedArgs.AddedIssues.Should().BeEquivalentTo(issueViz3);
- }
-
- [TestMethod]
- public void GetAnalysisInformation_NoInformation_ReturnsNull()
- {
- var testSubject = CreateTestSubject();
- testSubject.Set(Enumerable.Empty(), null);
-
- var result = testSubject.GetAnalysisInformation();
- result.Should().BeNull();
- }
-
- [TestMethod]
- public void GetAnalysisInformation_HasInformation_ReturnsInformation()
- {
- var analysisInformation = new AnalysisInformation("some branch", DateTimeOffset.Now);
-
- var testSubject = CreateTestSubject();
- testSubject.Set(Enumerable.Empty(), analysisInformation);
-
- var result = testSubject.GetAnalysisInformation();
- result.Should().BeSameAs(analysisInformation);
- }
-
- [TestMethod]
- public void Remove_IssueKeyIsNull_ArgumentNullException()
- {
- var testSubject = CreateTestSubject();
-
- Action act = () => testSubject.Remove(null);
-
- act.Should().Throw().And.ParamName.Should().Be("issueKey");
- }
-
- [TestMethod]
- public void Remove_IssueNotFound_NoIssuesInList_NoEventIsRaised()
- {
- var testSubject = CreateTestSubject();
-
- var callCount = 0;
- IssuesChangedEventArgs suppliedArgs = null;
- testSubject.IssuesChanged += (_, args) => { callCount++; suppliedArgs = args; };
-
- testSubject.Remove("some unknown key");
-
- callCount.Should().Be(0);
- testSubject.GetAll().Should().BeEmpty();
- }
-
- [TestMethod]
- public void Remove_IssueNotFound_NoIssueWithThisId_NoEventIsRaised()
- {
- var existingIssue = SetupIssueViz("key1");
-
- var testSubject = CreateTestSubject();
- testSubject.Set(new[] { existingIssue }, null);
-
- var callCount = 0;
- IssuesChangedEventArgs suppliedArgs = null;
- testSubject.IssuesChanged += (_, args) => { callCount++; suppliedArgs = args; };
-
- testSubject.Remove("some unknown key");
-
- callCount.Should().Be(0);
- testSubject.GetAll().Should().BeEquivalentTo(existingIssue);
- }
-
- [TestMethod]
- public void Remove_IssueFound_IssueIsRemovedAndEventIsRaised()
- {
- var existingIssue1 = SetupIssueViz("key1");
- var existingIssue2 = SetupIssueViz("key2");
- var existingIssue3 = SetupIssueViz("key3");
-
- var testSubject = CreateTestSubject();
- testSubject.Set(new[] {existingIssue1, existingIssue2, existingIssue3}, null);
-
- var callCount = 0;
- IssuesChangedEventArgs suppliedArgs = null;
- testSubject.IssuesChanged += (_, args) => { callCount++; suppliedArgs = args; };
-
- testSubject.Remove("key2");
-
- callCount.Should().Be(1);
- suppliedArgs.RemovedIssues.Should().BeEquivalentTo(existingIssue2);
- suppliedArgs.AddedIssues.Should().BeEmpty();
- testSubject.GetAll().Should().BeEquivalentTo(existingIssue1, existingIssue3);
- }
-
- [TestMethod]
- public void Remove_MultipleIssuesFoundWithSameId_FirstIssueIsRemovedAndEventIsRaised()
- {
- var existingIssue1 = SetupIssueViz("key1");
- var existingIssue2 = SetupIssueViz("key1");
- var existingIssue3 = SetupIssueViz("key1");
-
- var testSubject = CreateTestSubject();
- testSubject.Set(new[] { existingIssue1, existingIssue2, existingIssue3 }, null);
-
- var callCount = 0;
- IssuesChangedEventArgs suppliedArgs = null;
- testSubject.IssuesChanged += (_, args) => { callCount++; suppliedArgs = args; };
-
- testSubject.Remove("key1");
-
- callCount.Should().Be(1);
- suppliedArgs.RemovedIssues.Should().BeEquivalentTo(existingIssue1);
- suppliedArgs.AddedIssues.Should().BeEmpty();
- testSubject.GetAll().Should().BeEquivalentTo(existingIssue2, existingIssue3);
- }
-
- [TestMethod]
- public void Add_IssueIsNull_ArgumentNullException()
- {
- var testSubject = CreateTestSubject();
-
- Action act = () => testSubject.Add(null);
-
- act.Should().Throw().And.ParamName.Should().Be("issueVisualization");
- }
-
- [TestMethod]
- public void Add_NoAnalysisInformation_IssueIgnoredAndNoEventIsRaised()
- {
- var existingIssue = SetupIssueViz("key1");
-
- var testSubject = CreateTestSubject();
- testSubject.Set(new[] { existingIssue}, null);
-
- var callCount = 0;
- IssuesChangedEventArgs suppliedArgs = null;
- testSubject.IssuesChanged += (_, args) => { callCount++; suppliedArgs = args; };
-
- testSubject.Add(SetupIssueViz());
-
- callCount.Should().Be(0);
- testSubject.GetAll().Should().BeEquivalentTo(existingIssue);
- }
-
- [TestMethod]
- public void Add_HasAnalysisInformation_IssueAddedAndEventIsRaised()
- {
- var analysisInformation = new AnalysisInformation("some branch", DateTimeOffset.Now);
- var existingIssue = SetupIssueViz("key1");
-
- var testSubject = CreateTestSubject();
- testSubject.Set(new[] { existingIssue }, analysisInformation);
-
- var callCount = 0;
- IssuesChangedEventArgs suppliedArgs = null;
- testSubject.IssuesChanged += (_, args) => { callCount++; suppliedArgs = args; };
-
- var newIssue = SetupIssueViz();
- testSubject.Add(newIssue);
-
- callCount.Should().Be(1);
- suppliedArgs.RemovedIssues.Should().BeEmpty();
- suppliedArgs.AddedIssues.Should().BeEquivalentTo(newIssue);
- testSubject.GetAll().Should().BeEquivalentTo(existingIssue, newIssue);
- }
-
- [TestMethod]
- public void Add_DuplicateIssue_IssueIgnoredAndNoEventIsRaised()
- {
- var analysisInformation = new AnalysisInformation("some branch", DateTimeOffset.Now);
- var issueKey = "key1";
- var existingIssue = SetupIssueViz(issueKey);
-
- var testSubject = CreateTestSubject();
- testSubject.Set(new[] { existingIssue }, analysisInformation);
-
- var callCount = 0;
- IssuesChangedEventArgs suppliedArgs = null;
- testSubject.IssuesChanged += (_, args) => { callCount++; suppliedArgs = args; };
-
- var newIssue = SetupIssueViz(issueKey);
- testSubject.Add(newIssue);
-
- callCount.Should().Be(0);
- testSubject.GetAll().Should().BeEquivalentTo(existingIssue);
- }
-
- private IAnalysisIssueVisualization SetupIssueViz(string issueKey = null)
- {
- issueKey ??= Guid.NewGuid().ToString();
-
- var taintIssue = new Mock();
- taintIssue.Setup(x => x.IssueKey).Returns(issueKey);
-
- var issueViz = new Mock();
- issueViz.Setup(x => x.Issue).Returns(taintIssue.Object);
-
- return issueViz.Object;
- }
-
- private ITaintStore CreateTestSubject()
- {
- return new TaintStore();
- }
- }
-}
+// /*
+// * SonarLint for Visual Studio
+// * Copyright (C) 2016-2024 SonarSource SA
+// * mailto:info AT sonarsource DOT com
+// *
+// * This program is free software; you can redistribute it and/or
+// * modify it under the terms of the GNU Lesser General Public
+// * License as published by the Free Software Foundation; either
+// * version 3 of the License, or (at your option) any later version.
+// *
+// * This program is distributed in the hope that it will be useful,
+// * but WITHOUT ANY WARRANTY; without even the implied warranty of
+// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// * Lesser General Public License for more details.
+// *
+// * You should have received a copy of the GNU Lesser General Public License
+// * along with this program; if not, write to the Free Software Foundation,
+// * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+// */
+//
+// using System;
+// using System.ComponentModel.Composition;
+// using System.ComponentModel.Composition.Hosting;
+// using System.Linq;
+// using FluentAssertions;
+// using Microsoft.VisualStudio.TestTools.UnitTesting;
+// using Moq;
+// using SonarLint.VisualStudio.TestInfrastructure;
+// using SonarLint.VisualStudio.IssueVisualization.Models;
+// using SonarLint.VisualStudio.IssueVisualization.Security.IssuesStore;
+// using SonarLint.VisualStudio.IssueVisualization.Security.Taint;
+// using SonarLint.VisualStudio.IssueVisualization.Security.Taint.Models;
+//
+// namespace SonarLint.VisualStudio.IssueVisualization.Security.UnitTests.Taint
+// {
+// [TestClass]
+// public class TaintStoreTests
+// {
+// [TestMethod]
+// public void MefCtor_CheckExports()
+// {
+// var batch = new CompositionBatch();
+//
+// var storeImport = new SingleObjectImporter();
+// var issuesStoreImport = new SingleObjectImporter();
+// batch.AddPart(storeImport);
+// batch.AddPart(issuesStoreImport);
+//
+// var catalog = new TypeCatalog(typeof(TaintStore));
+// using var container = new CompositionContainer(catalog);
+// container.Compose(batch);
+//
+// storeImport.Import.Should().NotBeNull();
+// issuesStoreImport.Import.Should().NotBeNull();
+//
+// storeImport.Import.Should().BeSameAs(issuesStoreImport.Import);
+// }
+//
+// [TestMethod]
+// public void GetAll_ReturnsImmutableInstance()
+// {
+// var testSubject = CreateTestSubject();
+// var oldItems = new[] { SetupIssueViz(), SetupIssueViz() };
+// testSubject.Set(oldItems, new AnalysisInformation("some branch", DateTimeOffset.Now));
+//
+// var issuesList1 = testSubject.GetAll();
+// testSubject.Add(SetupIssueViz());
+// var issuesList2 = testSubject.GetAll();
+//
+// issuesList1.Count.Should().Be(2);
+// issuesList2.Count.Should().Be(3);
+// }
+//
+// [TestMethod]
+// public void Set_NullCollection_ArgumentNullException()
+// {
+// var testSubject = CreateTestSubject();
+//
+// Action act = () => testSubject.Set(null, null);
+//
+// act.Should().Throw().And.ParamName.Should().Be("issueVisualizations");
+// }
+//
+// [TestMethod]
+// public void Set_NoSubscribersToIssuesChangedEvent_NoException()
+// {
+// var testSubject = CreateTestSubject();
+//
+// Action act = () => testSubject.Set(new[] { SetupIssueViz() }, null);
+//
+// act.Should().NotThrow();
+// }
+//
+// [TestMethod]
+// public void Set_NoPreviousItems_NoNewItems_CollectionChangedAndEventRaised()
+// {
+// var testSubject = CreateTestSubject();
+//
+// var callCount = 0;
+// testSubject.IssuesChanged += (sender, args) => { callCount++; };
+//
+// testSubject.Set(Enumerable.Empty(), null);
+//
+// testSubject.GetAll().Should().BeEmpty();
+// callCount.Should().Be(1);
+// }
+//
+// [TestMethod]
+// public void Set_NoPreviousItems_HasNewItems_CollectionChangedAndEventRaised()
+// {
+// var testSubject = CreateTestSubject();
+//
+// var callCount = 0;
+// IssuesChangedEventArgs suppliedArgs = null;
+// testSubject.IssuesChanged += (sender, args) => { callCount++; suppliedArgs = args; };
+//
+// var newItems = new[] { SetupIssueViz(), SetupIssueViz() };
+// testSubject.Set(newItems, null);
+//
+// testSubject.GetAll().Should().BeEquivalentTo(newItems);
+// callCount.Should().Be(1);
+// suppliedArgs.RemovedIssues.Should().BeEmpty();
+// suppliedArgs.AddedIssues.Should().BeEquivalentTo(newItems);
+// }
+//
+// [TestMethod]
+// public void Set_HasPreviousItems_NoNewItems_CollectionChangedAndEventRaised()
+// {
+// var testSubject = CreateTestSubject();
+//
+// var oldItems = new[] { SetupIssueViz(), SetupIssueViz() };
+// testSubject.Set(oldItems, null);
+//
+// var callCount = 0;
+// IssuesChangedEventArgs suppliedArgs = null;
+// testSubject.IssuesChanged += (sender, args) => { callCount++; suppliedArgs = args; };
+//
+// testSubject.Set(Enumerable.Empty(), null);
+//
+// testSubject.GetAll().Should().BeEmpty();
+// callCount.Should().Be(1);
+// suppliedArgs.RemovedIssues.Should().BeEquivalentTo(oldItems);
+// suppliedArgs.AddedIssues.Should().BeEmpty();
+// }
+//
+// [TestMethod]
+// public void Set_HasPreviousItems_HasNewItems_CollectionChangedAndEventRaised()
+// {
+// var testSubject = CreateTestSubject();
+//
+// var oldItems = new[] { SetupIssueViz(), SetupIssueViz() };
+// testSubject.Set(oldItems, null);
+//
+// var callCount = 0;
+// IssuesChangedEventArgs suppliedArgs = null;
+// testSubject.IssuesChanged += (sender, args) => { callCount++; suppliedArgs = args; };
+//
+// var newItems = new[] { SetupIssueViz(), SetupIssueViz() };
+// testSubject.Set(newItems, null);
+//
+// testSubject.GetAll().Should().BeEquivalentTo(newItems);
+// callCount.Should().Be(1);
+// suppliedArgs.RemovedIssues.Should().BeEquivalentTo(oldItems);
+// suppliedArgs.AddedIssues.Should().BeEquivalentTo(newItems);
+// }
+//
+// [TestMethod]
+// public void Set_HasPreviousItems_HasSomeNewItems_CollectionChangedAndEventRaised()
+// {
+// var testSubject = CreateTestSubject();
+//
+// var issueViz1 = SetupIssueViz("key1");
+// var issueViz2 = SetupIssueViz("key2");
+// var issueViz2NewObject = SetupIssueViz("key2");
+// var issueViz3 = SetupIssueViz("key3");
+//
+// var oldItems = new[] { issueViz1, issueViz2 };
+// testSubject.Set(oldItems, null);
+//
+// var callCount = 0;
+// IssuesChangedEventArgs suppliedArgs = null;
+// testSubject.IssuesChanged += (sender, args) => { callCount++; suppliedArgs = args; };
+//
+// var newItems = new[] { issueViz2NewObject, issueViz3};
+// testSubject.Set(newItems, null);
+//
+// testSubject.GetAll().Should().BeEquivalentTo(newItems);
+// callCount.Should().Be(1);
+// suppliedArgs.RemovedIssues.Should().BeEquivalentTo(issueViz1);
+// suppliedArgs.AddedIssues.Should().BeEquivalentTo(issueViz3);
+// }
+//
+// [TestMethod]
+// public void GetAnalysisInformation_NoInformation_ReturnsNull()
+// {
+// var testSubject = CreateTestSubject();
+// testSubject.Set(Enumerable.Empty(), null);
+//
+// var result = testSubject.GetAnalysisInformation();
+// result.Should().BeNull();
+// }
+//
+// [TestMethod]
+// public void GetAnalysisInformation_HasInformation_ReturnsInformation()
+// {
+// var analysisInformation = new AnalysisInformation("some branch", DateTimeOffset.Now);
+//
+// var testSubject = CreateTestSubject();
+// testSubject.Set(Enumerable.Empty(), analysisInformation);
+//
+// var result = testSubject.GetAnalysisInformation();
+// result.Should().BeSameAs(analysisInformation);
+// }
+//
+// [TestMethod]
+// public void Remove_IssueKeyIsNull_ArgumentNullException()
+// {
+// var testSubject = CreateTestSubject();
+//
+// Action act = () => testSubject.Remove(null);
+//
+// act.Should().Throw().And.ParamName.Should().Be("issueKey");
+// }
+//
+// [TestMethod]
+// public void Remove_IssueNotFound_NoIssuesInList_NoEventIsRaised()
+// {
+// var testSubject = CreateTestSubject();
+//
+// var callCount = 0;
+// IssuesChangedEventArgs suppliedArgs = null;
+// testSubject.IssuesChanged += (_, args) => { callCount++; suppliedArgs = args; };
+//
+// testSubject.Remove("some unknown key");
+//
+// callCount.Should().Be(0);
+// testSubject.GetAll().Should().BeEmpty();
+// }
+//
+// [TestMethod]
+// public void Remove_IssueNotFound_NoIssueWithThisId_NoEventIsRaised()
+// {
+// var existingIssue = SetupIssueViz("key1");
+//
+// var testSubject = CreateTestSubject();
+// testSubject.Set(new[] { existingIssue }, null);
+//
+// var callCount = 0;
+// IssuesChangedEventArgs suppliedArgs = null;
+// testSubject.IssuesChanged += (_, args) => { callCount++; suppliedArgs = args; };
+//
+// testSubject.Remove("some unknown key");
+//
+// callCount.Should().Be(0);
+// testSubject.GetAll().Should().BeEquivalentTo(existingIssue);
+// }
+//
+// [TestMethod]
+// public void Remove_IssueFound_IssueIsRemovedAndEventIsRaised()
+// {
+// var existingIssue1 = SetupIssueViz("key1");
+// var existingIssue2 = SetupIssueViz("key2");
+// var existingIssue3 = SetupIssueViz("key3");
+//
+// var testSubject = CreateTestSubject();
+// testSubject.Set(new[] {existingIssue1, existingIssue2, existingIssue3}, null);
+//
+// var callCount = 0;
+// IssuesChangedEventArgs suppliedArgs = null;
+// testSubject.IssuesChanged += (_, args) => { callCount++; suppliedArgs = args; };
+//
+// testSubject.Remove("key2");
+//
+// callCount.Should().Be(1);
+// suppliedArgs.RemovedIssues.Should().BeEquivalentTo(existingIssue2);
+// suppliedArgs.AddedIssues.Should().BeEmpty();
+// testSubject.GetAll().Should().BeEquivalentTo(existingIssue1, existingIssue3);
+// }
+//
+// [TestMethod]
+// public void Remove_MultipleIssuesFoundWithSameId_FirstIssueIsRemovedAndEventIsRaised()
+// {
+// var existingIssue1 = SetupIssueViz("key1");
+// var existingIssue2 = SetupIssueViz("key1");
+// var existingIssue3 = SetupIssueViz("key1");
+//
+// var testSubject = CreateTestSubject();
+// testSubject.Set(new[] { existingIssue1, existingIssue2, existingIssue3 }, null);
+//
+// var callCount = 0;
+// IssuesChangedEventArgs suppliedArgs = null;
+// testSubject.IssuesChanged += (_, args) => { callCount++; suppliedArgs = args; };
+//
+// testSubject.Remove("key1");
+//
+// callCount.Should().Be(1);
+// suppliedArgs.RemovedIssues.Should().BeEquivalentTo(existingIssue1);
+// suppliedArgs.AddedIssues.Should().BeEmpty();
+// testSubject.GetAll().Should().BeEquivalentTo(existingIssue2, existingIssue3);
+// }
+//
+// [TestMethod]
+// public void Add_IssueIsNull_ArgumentNullException()
+// {
+// var testSubject = CreateTestSubject();
+//
+// Action act = () => testSubject.Add(null);
+//
+// act.Should().Throw().And.ParamName.Should().Be("issueVisualization");
+// }
+//
+// [TestMethod]
+// public void Add_NoAnalysisInformation_IssueIgnoredAndNoEventIsRaised()
+// {
+// var existingIssue = SetupIssueViz("key1");
+//
+// var testSubject = CreateTestSubject();
+// testSubject.Set(new[] { existingIssue}, null);
+//
+// var callCount = 0;
+// IssuesChangedEventArgs suppliedArgs = null;
+// testSubject.IssuesChanged += (_, args) => { callCount++; suppliedArgs = args; };
+//
+// testSubject.Add(SetupIssueViz());
+//
+// callCount.Should().Be(0);
+// testSubject.GetAll().Should().BeEquivalentTo(existingIssue);
+// }
+//
+// [TestMethod]
+// public void Add_HasAnalysisInformation_IssueAddedAndEventIsRaised()
+// {
+// var analysisInformation = new AnalysisInformation("some branch", DateTimeOffset.Now);
+// var existingIssue = SetupIssueViz("key1");
+//
+// var testSubject = CreateTestSubject();
+// testSubject.Set(new[] { existingIssue }, analysisInformation);
+//
+// var callCount = 0;
+// IssuesChangedEventArgs suppliedArgs = null;
+// testSubject.IssuesChanged += (_, args) => { callCount++; suppliedArgs = args; };
+//
+// var newIssue = SetupIssueViz();
+// testSubject.Add(newIssue);
+//
+// callCount.Should().Be(1);
+// suppliedArgs.RemovedIssues.Should().BeEmpty();
+// suppliedArgs.AddedIssues.Should().BeEquivalentTo(newIssue);
+// testSubject.GetAll().Should().BeEquivalentTo(existingIssue, newIssue);
+// }
+//
+// [TestMethod]
+// public void Add_DuplicateIssue_IssueIgnoredAndNoEventIsRaised()
+// {
+// var analysisInformation = new AnalysisInformation("some branch", DateTimeOffset.Now);
+// var issueKey = "key1";
+// var existingIssue = SetupIssueViz(issueKey);
+//
+// var testSubject = CreateTestSubject();
+// testSubject.Set(new[] { existingIssue }, analysisInformation);
+//
+// var callCount = 0;
+// IssuesChangedEventArgs suppliedArgs = null;
+// testSubject.IssuesChanged += (_, args) => { callCount++; suppliedArgs = args; };
+//
+// var newIssue = SetupIssueViz(issueKey);
+// testSubject.Add(newIssue);
+//
+// callCount.Should().Be(0);
+// testSubject.GetAll().Should().BeEquivalentTo(existingIssue);
+// }
+//
+// private IAnalysisIssueVisualization SetupIssueViz(string issueKey = null)
+// {
+// issueKey ??= Guid.NewGuid().ToString();
+//
+// var taintIssue = new Mock();
+// taintIssue.Setup(x => x.IssueKey).Returns(issueKey);
+//
+// var issueViz = new Mock();
+// issueViz.Setup(x => x.Issue).Returns(taintIssue.Object);
+//
+// return issueViz.Object;
+// }
+//
+// private ITaintStore CreateTestSubject()
+// {
+// return new TaintStore();
+// }
+// }
+// }
diff --git a/src/IssueViz.Security/Taint/TaintIssuesBindingMonitor.cs b/src/IssueViz.Security/Taint/TaintIssuesBindingMonitor.cs
deleted file mode 100644
index 6cfc54395b..0000000000
--- a/src/IssueViz.Security/Taint/TaintIssuesBindingMonitor.cs
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * SonarLint for Visual Studio
- * Copyright (C) 2016-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-using System;
-using System.ComponentModel.Composition;
-using System.Threading.Tasks;
-using SonarLint.VisualStudio.Core;
-using SonarLint.VisualStudio.Core.Binding;
-
-namespace SonarLint.VisualStudio.IssueVisualization.Security.Taint
-{
- ///
- /// Listens to binding changes and triggers fetching of taint vulnerabilities from the connected server.
- /// Doesn't do initial sync - only triggers the fetch when the binding changes.
- ///
- internal interface ITaintIssuesBindingMonitor : IDisposable
- {
- }
-
- [Export(typeof(ITaintIssuesBindingMonitor))]
- [PartCreationPolicy(CreationPolicy.Shared)]
- internal sealed class TaintIssuesBindingMonitor : ITaintIssuesBindingMonitor
- {
- private readonly IActiveSolutionBoundTracker activeSolutionBoundTracker;
- private readonly IFolderWorkspaceMonitor folderWorkspaceMonitor;
- private readonly ITaintIssuesSynchronizer taintIssuesSynchronizer;
-
- [ImportingConstructor]
- public TaintIssuesBindingMonitor(IActiveSolutionBoundTracker activeSolutionBoundTracker,
- IFolderWorkspaceMonitor folderWorkspaceMonitor,
- ITaintIssuesSynchronizer taintIssuesSynchronizer)
- {
- this.activeSolutionBoundTracker = activeSolutionBoundTracker;
- this.folderWorkspaceMonitor = folderWorkspaceMonitor;
- this.taintIssuesSynchronizer = taintIssuesSynchronizer;
-
- folderWorkspaceMonitor.FolderWorkspaceInitialized += FolderWorkspaceInitializedEvent_FolderWorkspaceInitialized;
- activeSolutionBoundTracker.SolutionBindingChanged += ActiveSolutionBoundTracker_SolutionBindingChanged;
- activeSolutionBoundTracker.SolutionBindingUpdated += ActiveSolutionBoundTracker_SolutionBindingUpdated;
- }
-
- private async void FolderWorkspaceInitializedEvent_FolderWorkspaceInitialized(object sender, EventArgs e)
- {
- await Sync();
- }
-
- private async void ActiveSolutionBoundTracker_SolutionBindingUpdated(object sender, EventArgs e)
- {
- await Sync();
- }
-
- private async void ActiveSolutionBoundTracker_SolutionBindingChanged(object sender, ActiveSolutionBindingEventArgs e)
- {
- await Sync();
- }
-
- private async Task Sync()
- {
- await taintIssuesSynchronizer.SynchronizeWithServer();
- }
-
- public void Dispose()
- {
- folderWorkspaceMonitor.FolderWorkspaceInitialized -= FolderWorkspaceInitializedEvent_FolderWorkspaceInitialized;
- activeSolutionBoundTracker.SolutionBindingChanged -= ActiveSolutionBoundTracker_SolutionBindingChanged;
- activeSolutionBoundTracker.SolutionBindingUpdated -= ActiveSolutionBoundTracker_SolutionBindingUpdated;
- }
- }
-}
diff --git a/src/IssueViz.Security/Taint/TaintIssuesConfigurationScopeMonitor.cs b/src/IssueViz.Security/Taint/TaintIssuesConfigurationScopeMonitor.cs
new file mode 100644
index 0000000000..c1eb071c4e
--- /dev/null
+++ b/src/IssueViz.Security/Taint/TaintIssuesConfigurationScopeMonitor.cs
@@ -0,0 +1,56 @@
+/*
+ * SonarLint for Visual Studio
+ * Copyright (C) 2016-2024 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+using System.ComponentModel.Composition;
+using Microsoft.VisualStudio.Threading;
+using SonarLint.VisualStudio.SLCore.State;
+
+namespace SonarLint.VisualStudio.IssueVisualization.Security.Taint
+{
+ ///
+ /// Listens to binding changes and triggers fetching of taint vulnerabilities from the connected server.
+ /// Doesn't do initial sync - only triggers the fetch when the binding changes.
+ ///
+ internal interface ITaintIssuesBindingMonitor : IDisposable;
+
+ [Export(typeof(ITaintIssuesBindingMonitor))]
+ [PartCreationPolicy(CreationPolicy.Shared)]
+ internal sealed class TaintIssuesConfigurationScopeMonitor : ITaintIssuesBindingMonitor
+ {
+ private readonly IActiveConfigScopeTracker activeConfigScopeTracker;
+ private readonly ITaintIssuesSynchronizer taintIssuesSynchronizer;
+
+ [ImportingConstructor]
+ public TaintIssuesConfigurationScopeMonitor(IActiveConfigScopeTracker activeConfigScopeTracker,
+ ITaintIssuesSynchronizer taintIssuesSynchronizer)
+ {
+ this.activeConfigScopeTracker = activeConfigScopeTracker;
+ this.taintIssuesSynchronizer = taintIssuesSynchronizer;
+
+ this.activeConfigScopeTracker.CurrentConfigurationScopeChanged += ActiveConfigScopeTrackerOnCurrentConfigurationScopeChanged;
+ }
+
+ private void ActiveConfigScopeTrackerOnCurrentConfigurationScopeChanged(object sender, EventArgs e) =>
+ taintIssuesSynchronizer.UpdateTaintVulnerabilitiesAsync(activeConfigScopeTracker.Current).Forget();
+
+ public void Dispose() =>
+ activeConfigScopeTracker.CurrentConfigurationScopeChanged -= ActiveConfigScopeTrackerOnCurrentConfigurationScopeChanged;
+ }
+}
diff --git a/src/IssueViz.Security/Taint/TaintIssuesSynchronizer.cs b/src/IssueViz.Security/Taint/TaintIssuesSynchronizer.cs
index 826aca1196..31ffecff04 100644
--- a/src/IssueViz.Security/Taint/TaintIssuesSynchronizer.cs
+++ b/src/IssueViz.Security/Taint/TaintIssuesSynchronizer.cs
@@ -18,185 +18,148 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-using System;
using System.ComponentModel.Composition;
-using System.Diagnostics;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
using SonarLint.VisualStudio.Core;
-using SonarLint.VisualStudio.Core.Binding;
+using SonarLint.VisualStudio.Core.Synchronization;
using SonarLint.VisualStudio.Infrastructure.VS;
-using SonarLint.VisualStudio.IssueVisualization.Models;
using SonarLint.VisualStudio.IssueVisualization.Security.Taint.TaintList;
-using SonarQube.Client;
+using SonarLint.VisualStudio.SLCore.Core;
+using SonarLint.VisualStudio.SLCore.Service.Taint;
+using SonarLint.VisualStudio.SLCore.State;
using VSShellInterop = Microsoft.VisualStudio.Shell.Interop;
-namespace SonarLint.VisualStudio.IssueVisualization.Security.Taint
+namespace SonarLint.VisualStudio.IssueVisualization.Security.Taint;
+
+internal interface ITaintIssuesSynchronizer
{
- internal interface ITaintIssuesSynchronizer
- {
- ///
- /// Fetches taint vulnerabilities from the server, converts them into visualizations and populates .
- ///
- Task SynchronizeWithServer();
- }
+ ///
+ /// Fetches taint vulnerabilities from the server, converts them into visualizations and populates .
+ ///
+ Task UpdateTaintVulnerabilitiesAsync(ConfigurationScope configurationScope);
+}
- [Export(typeof(ITaintIssuesSynchronizer))]
- [PartCreationPolicy(CreationPolicy.Shared)]
- internal sealed class TaintIssuesSynchronizer : ITaintIssuesSynchronizer
+[Export(typeof(ITaintIssuesSynchronizer))]
+[PartCreationPolicy(CreationPolicy.Shared)]
+internal sealed class TaintIssuesSynchronizer : ITaintIssuesSynchronizer
+{
+ private readonly IAsyncLock asyncLock;
+ private readonly ITaintIssueToIssueVisualizationConverter converter;
+ private readonly ILogger logger;
+ private readonly ISLCoreServiceProvider slCoreServiceProvider;
+ private readonly ITaintStore taintStore;
+ private readonly IThreadHandling threadHandling;
+ private readonly IToolWindowService toolWindowService;
+ private readonly IVsUIServiceOperation vSServiceOperation;
+
+ [ImportingConstructor]
+ public TaintIssuesSynchronizer(
+ ITaintStore taintStore,
+ ISLCoreServiceProvider slCoreServiceProvider,
+ ITaintIssueToIssueVisualizationConverter converter,
+ IToolWindowService toolWindowService,
+ IStatefulServerBranchProvider serverBranchProvider,
+ IVsUIServiceOperation vSServiceOperation,
+ IThreadHandling threadHandling,
+ IAsyncLockFactory asyncLockFactory,
+ ILogger logger)
{
- private static readonly Version MinimumRequiredSonarQubeVersion = new Version(8, 6);
-
- private readonly ITaintStore taintStore;
- private readonly ISonarQubeService sonarQubeService;
- private readonly ITaintIssueToIssueVisualizationConverter converter;
- private readonly IConfigurationProvider configurationProvider;
- private readonly IToolWindowService toolWindowService;
- private readonly IStatefulServerBranchProvider serverBranchProvider;
- private readonly IVsUIServiceOperation vSServiceOperation;
- private readonly ILogger logger;
-
- [ImportingConstructor]
- public TaintIssuesSynchronizer(ITaintStore taintStore,
- ISonarQubeService sonarQubeService,
- ITaintIssueToIssueVisualizationConverter converter,
- IConfigurationProvider configurationProvider,
- IToolWindowService toolWindowService,
- IStatefulServerBranchProvider serverBranchProvider,
- IVsUIServiceOperation vSServiceOperation,
- ILogger logger)
- {
- this.taintStore = taintStore;
- this.sonarQubeService = sonarQubeService;
- this.converter = converter;
- this.configurationProvider = configurationProvider;
- this.toolWindowService = toolWindowService;
- this.serverBranchProvider = serverBranchProvider;
- this.vSServiceOperation = vSServiceOperation;
- this.logger = logger;
- }
-
- public async Task SynchronizeWithServer()
- {
- return; // todo https://sonarsource.atlassian.net/browse/SLVS-1592
-
- // try
- // {
- // var bindingConfiguration = configurationProvider.GetConfiguration();
- //
- // if (IsStandalone(bindingConfiguration) || !IsConnected(out var serverInfo) || !IsFeatureSupported(serverInfo))
- // {
- // HandleNoTaintIssues();
- // return;
- // }
- //
- // var projectKey = bindingConfiguration.Project.ServerProjectKey;
- // var serverBranch = await serverBranchProvider.GetServerBranchNameAsync(CancellationToken.None);
- //
- // var taintVulnerabilities = await sonarQubeService.GetTaintVulnerabilitiesAsync(projectKey,
- // serverBranch,
- // CancellationToken.None);
- //
- // logger.WriteLine(TaintResources.Synchronizer_NumberOfServerIssues, taintVulnerabilities.Count);
- //
- // var analysisInformation = await GetAnalysisInformation(projectKey, serverBranch);
- // var taintIssueVizs = taintVulnerabilities.Select(converter.Convert).ToArray();
- // taintStore.Set(taintIssueVizs, analysisInformation);
- //
- // var hasTaintIssues = taintVulnerabilities.Count > 0;
- //
- // if (!hasTaintIssues)
- // {
- // UpdateTaintIssuesUIContext(false);
- // }
- // else
- // {
- // UpdateTaintIssuesUIContext(true);
- //
- // // We need the tool window content to exist so the issues are filtered and the
- // // tool window caption is updated. See the "EnsureToolWindowExists" method comment
- // // for more information.
- // toolWindowService.EnsureToolWindowExists(TaintToolWindow.ToolWindowId);
- // }
- // }
- // catch (Exception ex) when (!ErrorHandler.IsCriticalException(ex))
- // {
- // logger.WriteLine(TaintResources.Synchronizer_Failure, ex);
- // HandleNoTaintIssues();
- // }
- }
+ this.taintStore = taintStore;
+ this.slCoreServiceProvider = slCoreServiceProvider;
+ this.converter = converter;
+ this.toolWindowService = toolWindowService;
+ this.vSServiceOperation = vSServiceOperation;
+ asyncLock = asyncLockFactory.Create();
+ this.threadHandling = threadHandling;
+ this.logger = logger;
+ }
- private bool IsStandalone(BindingConfiguration bindingConfiguration)
+ public Task UpdateTaintVulnerabilitiesAsync(ConfigurationScope configurationScope) =>
+ threadHandling.RunOnBackgroundThread(async () =>
{
- if (bindingConfiguration.Mode == SonarLintMode.Standalone)
+ using (await asyncLock.AcquireAsync())
{
- logger.WriteLine(TaintResources.Synchronizer_NotInConnectedMode);
- return true;
+ await PerformSynchronizationInternalAsync(configurationScope);
}
+ });
- return false;
- }
-
- private bool IsConnected(out ServerInfo serverInfo)
+ private async Task PerformSynchronizationInternalAsync(ConfigurationScope configurationScope)
+ {
+ try
{
- serverInfo = sonarQubeService.GetServerInfo();
-
- if (serverInfo != null)
+ if (IsStandalone(configurationScope) || !slCoreServiceProvider.TryGetTransientService(out ITaintVulnerabilityTrackingSlCoreService taintService))
{
- return true;
+ HandleNoTaintIssues();
+ return;
}
- logger.WriteLine(TaintResources.Synchronizer_ServerNotConnected);
- return false;
- }
-
- private bool IsFeatureSupported(ServerInfo serverInfo)
- {
- if (serverInfo.ServerType == ServerType.SonarCloud ||
- serverInfo.Version >= MinimumRequiredSonarQubeVersion)
+ if (!IsConfigScopeReady(configurationScope) || IsAlreadyInitializedForConfigScope(configurationScope))
{
- return true;
+ return;
}
- logger.WriteLine(TaintResources.Synchronizer_UnsupportedSQVersion, serverInfo.Version, DocumentationLinks.TaintVulnerabilities);
- return false;
- }
+ var taintsResponse = await taintService.ListAllAsync(new ListAllTaintsParams(configurationScope.Id, true));
+ logger.WriteLine(TaintResources.Synchronizer_NumberOfServerIssues, taintsResponse.taintVulnerabilities.Count);
- private async Task GetAnalysisInformation(string projectKey, string branchName)
- {
- Debug.Assert(branchName != null, "BranchName should not be null when in Connected Mode");
+ taintStore.Set(taintsResponse.taintVulnerabilities.Select(x => converter.Convert(x, configurationScope.RootPath)), configurationScope.Id);
- var branches = await sonarQubeService.GetProjectBranchesAsync(projectKey, CancellationToken.None);
+ HandleUIContextUpdate(taintsResponse);
+ }
+ catch (Exception ex) when (!ErrorHandler.IsCriticalException(ex))
+ {
+ logger.WriteLine(TaintResources.Synchronizer_Failure, ex);
+ HandleNoTaintIssues();
+ }
+ }
- var issuesBranch = branches.FirstOrDefault(x => x.Name.Equals(branchName));
+ private static bool IsConfigScopeReady(ConfigurationScope configurationScope) => configurationScope.RootPath is not null;
- Debug.Assert(issuesBranch != null, "Should always find a matching branch");
+ private bool IsAlreadyInitializedForConfigScope(ConfigurationScope configurationScope) => taintStore.ConfigurationScope == configurationScope.Id;
- return new AnalysisInformation(issuesBranch.Name, issuesBranch.LastAnalysisTimestamp);
- }
+ private void HandleUIContextUpdate(ListAllTaintsResponse taintsResponse)
+ {
+ var hasTaintIssues = taintsResponse.taintVulnerabilities.Count > 0;
- private void HandleNoTaintIssues()
+ if (!hasTaintIssues)
{
- ClearStore();
UpdateTaintIssuesUIContext(false);
}
-
- private void ClearStore()
+ else
{
- taintStore.Set(Enumerable.Empty(), null);
+ UpdateTaintIssuesUIContext(true);
+
+ // We need the tool window content to exist so the issues are filtered and the
+ // tool window caption is updated. See the "EnsureToolWindowExists" method comment
+ // for more information.
+ toolWindowService.EnsureToolWindowExists(TaintToolWindow.ToolWindowId);
}
+ }
- private void UpdateTaintIssuesUIContext(bool hasTaintIssues)
+ private bool IsStandalone(ConfigurationScope configurationScope)
+ {
+ if (configurationScope is { SonarProjectId: not null })
{
- vSServiceOperation.Execute(
- monitorSelection =>
- {
- Guid localGuid = TaintIssuesExistUIContext.Guid;
-
- monitorSelection.GetCmdUIContextCookie(ref localGuid, out var cookie);
- monitorSelection.SetCmdUIContext(cookie, hasTaintIssues ? 1 : 0);
- });
+ return false;
}
+
+ logger.WriteLine(TaintResources.Synchronizer_NotInConnectedMode);
+ return true;
+ }
+
+ private void HandleNoTaintIssues()
+ {
+ ClearStore();
+ UpdateTaintIssuesUIContext(false);
}
+
+ private void ClearStore() => taintStore.Set([], null);
+
+ private void UpdateTaintIssuesUIContext(bool hasTaintIssues) =>
+ vSServiceOperation.Execute(
+ monitorSelection =>
+ {
+ var localGuid = TaintIssuesExistUIContext.Guid;
+
+ monitorSelection.GetCmdUIContextCookie(ref localGuid, out var cookie);
+ monitorSelection.SetCmdUIContext(cookie, hasTaintIssues ? 1 : 0);
+ });
}
diff --git a/src/IssueViz.Security/Taint/TaintList/ViewModels/TaintIssuesControlViewModel.cs b/src/IssueViz.Security/Taint/TaintList/ViewModels/TaintIssuesControlViewModel.cs
index ecdf4726cb..e71ec7debf 100644
--- a/src/IssueViz.Security/Taint/TaintList/ViewModels/TaintIssuesControlViewModel.cs
+++ b/src/IssueViz.Security/Taint/TaintList/ViewModels/TaintIssuesControlViewModel.cs
@@ -164,7 +164,7 @@ INavigateToRuleDescriptionCommand navigateToRuleDescriptionCommand
ISonarQubeService sonarQubeService,
INavigateToRuleDescriptionCommand navigateToRuleDescriptionCommand,
IThreadHandling threadHandling)
- {
+ {
this.threadHandling = threadHandling;
unfilteredIssues = new ObservableCollection();
AllowMultiThreadedAccessToIssuesCollection();
@@ -301,7 +301,7 @@ private void UpdateIssues()
taintIssueViewModel.TaintIssueViz.PropertyChanged += OnTaintIssuePropertyChanged;
}
- AnalysisInformation = store.GetAnalysisInformation();
+ AnalysisInformation = new AnalysisInformation("stub", DateTimeOffset.Now);
NotifyPropertyChanged(nameof(HasServerIssues));
NotifyPropertyChanged(nameof(AnalysisInformation));
diff --git a/src/IssueViz.Security/Taint/TaintStore.cs b/src/IssueViz.Security/Taint/TaintStore.cs
index 7120f10c49..77b2f5efb0 100644
--- a/src/IssueViz.Security/Taint/TaintStore.cs
+++ b/src/IssueViz.Security/Taint/TaintStore.cs
@@ -18,10 +18,7 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-using System;
-using System.Collections.Generic;
using System.ComponentModel.Composition;
-using System.Linq;
using SonarLint.VisualStudio.IssueVisualization.Models;
using SonarLint.VisualStudio.IssueVisualization.Security.IssuesStore;
using SonarLint.VisualStudio.IssueVisualization.Security.Taint.Models;
@@ -34,12 +31,9 @@ internal interface ITaintStore : IIssuesStore
/// Removes all existing visualizations and initializes the store to the given collection.
/// Can be called multiple times.
///
- void Set(IEnumerable issueVisualizations, AnalysisInformation analysisInformation);
+ void Set(IEnumerable issueVisualizations, string newConfigurationScope);
- ///
- /// Returns additional analysis information for the existing visualizations in the store.
- ///
- AnalysisInformation GetAnalysisInformation();
+ string ConfigurationScope { get; }
///
/// Add the given issue to the existing list of visualizations.
@@ -61,21 +55,19 @@ internal sealed class TaintStore : ITaintStore
{
public event EventHandler IssuesChanged;
- private static readonly object Locker = new object();
+ private readonly object locker = new object();
+ private string configurationScope;
private List taintVulnerabilities = new List();
- private AnalysisInformation analysisInformation;
public IReadOnlyCollection GetAll()
{
- lock (Locker)
+ lock (locker)
{
return taintVulnerabilities.ToList();
}
}
- public AnalysisInformation GetAnalysisInformation() => analysisInformation;
-
public void Add(IAnalysisIssueVisualization issueVisualization)
{
if (issueVisualization == null)
@@ -83,9 +75,9 @@ public void Add(IAnalysisIssueVisualization issueVisualization)
throw new ArgumentNullException(nameof(issueVisualization));
}
- lock (Locker)
+ lock (locker)
{
- if (analysisInformation == null)
+ if (configurationScope == null)
{
return;
}
@@ -108,8 +100,13 @@ public void Remove(string issueKey)
throw new ArgumentNullException(nameof(issueKey));
}
- lock (Locker)
+ lock (locker)
{
+ if (configurationScope == null)
+ {
+ return;
+ }
+
var indexToRemove =
taintVulnerabilities.FindIndex(issueViz => ((ITaintIssue)issueViz.Issue).IssueKey.Equals(issueKey));
@@ -125,17 +122,16 @@ public void Remove(string issueKey)
}
}
- public void Set(IEnumerable issueVisualizations, AnalysisInformation analysisInformation)
+ public void Set(IEnumerable issueVisualizations, string newConfigurationScope)
{
if (issueVisualizations == null)
{
throw new ArgumentNullException(nameof(issueVisualizations));
}
- lock (Locker)
+ lock (locker)
{
- this.analysisInformation = analysisInformation;
-
+ configurationScope = newConfigurationScope;
var oldIssues = taintVulnerabilities;
taintVulnerabilities = issueVisualizations.ToList();
@@ -146,6 +142,17 @@ public void Set(IEnumerable issueVisualizations, An
}
}
+ public string ConfigurationScope
+ {
+ get
+ {
+ lock (locker)
+ {
+ return configurationScope;
+ }
+ }
+ }
+
private void NotifyIssuesChanged(
IReadOnlyCollection removedIssues,
IReadOnlyCollection addedIssues)
diff --git a/src/IssueViz.Security/Taint/TaintSyncPackage.cs b/src/IssueViz.Security/Taint/TaintSyncPackage.cs
index c58e673612..496d75499d 100644
--- a/src/IssueViz.Security/Taint/TaintSyncPackage.cs
+++ b/src/IssueViz.Security/Taint/TaintSyncPackage.cs
@@ -29,6 +29,7 @@
using SonarLint.VisualStudio.Core.Binding;
using SonarLint.VisualStudio.Infrastructure.VS;
using SonarLint.VisualStudio.IssueVisualization.Security.Taint.ServerSentEvents;
+using SonarLint.VisualStudio.SLCore.State;
using Task = System.Threading.Tasks.Task;
namespace SonarLint.VisualStudio.IssueVisualization.Security.Taint
@@ -69,7 +70,7 @@ protected override async Task InitializeAsync(CancellationToken cancellationToke
await ThreadHandling.Instance.SwitchToBackgroundThread();
- await taintIssuesSynchronizer.SynchronizeWithServer();
+ await taintIssuesSynchronizer.UpdateTaintVulnerabilitiesAsync(componentModel.GetService().Current);
taintServerEventsListener.ListenAsync().Forget();
logger.WriteLine(TaintResources.SyncPackage_Initialized);