Skip to content

Commit

Permalink
SLVS-1853 Refactor the RoslynSettingsFileSynchronizer to not use Serv…
Browse files Browse the repository at this point in the history
…erIssueStore (#6029)
  • Loading branch information
gabriela-trutan-sonarsource committed Mar 4, 2025
1 parent bb2b032 commit d2ae5c9
Show file tree
Hide file tree
Showing 19 changed files with 1,182 additions and 253 deletions.
2 changes: 1 addition & 1 deletion src/ConnectedMode/Suppressions/ISuppressionUpdater.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ namespace SonarLint.VisualStudio.ConnectedMode.Suppressions;
/// <summary>
/// Fetches suppressed issues from the server and raises events. This is mainly needed for Roslyn languages
/// </summary>
internal interface ISuppressionUpdater
public interface ISuppressionUpdater
{
/// <summary>
/// Fetches all available suppressions from the server and raises the <see cref="SuppressedIssuesReloaded"/> event.
Expand Down
13 changes: 6 additions & 7 deletions src/Integration.Vsix/SonarLintIntegrationPackage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Threading;
using SonarLint.VisualStudio.ConnectedMode.UI;
using SonarLint.VisualStudio.Core;
using SonarLint.VisualStudio.Infrastructure.VS;
Expand Down Expand Up @@ -85,9 +84,9 @@ private async Task InitOnUIThreadAsync()

IServiceProvider serviceProvider = this;

this.commandManager = new PackageCommandManager(serviceProvider.GetService<IMenuCommandService>());
commandManager = new PackageCommandManager(serviceProvider.GetService<IMenuCommandService>());

this.commandManager.Initialize(
commandManager.Initialize(
serviceProvider.GetMefService<IProjectPropertyManager>(),
serviceProvider.GetMefService<IOutputWindowService>(),
serviceProvider.GetMefService<IShowInBrowserService>(),
Expand All @@ -96,8 +95,8 @@ private async Task InitOnUIThreadAsync()
serviceProvider.GetMefService<IConnectedModeBindingServices>(),
serviceProvider.GetMefService<IConnectedModeUIManager>());

this.roslynSettingsFileSynchronizer = await this.GetMefServiceAsync<IRoslynSettingsFileSynchronizer>();
roslynSettingsFileSynchronizer.UpdateFileStorageAsync().Forget(); // don't wait for it to finish
// make sure roslynSettingsFileSynchronizer is initialized
roslynSettingsFileSynchronizer = await this.GetMefServiceAsync<IRoslynSettingsFileSynchronizer>();
Debug.Assert(threadHandling.CheckAccess(), "Still expecting to be on the UI thread");

logger.WriteLine(Strings.SL_InitializationComplete);
Expand All @@ -114,8 +113,8 @@ protected override void Dispose(bool disposing)
base.Dispose(disposing);
if (disposing)
{
this.roslynSettingsFileSynchronizer?.Dispose();
this.roslynSettingsFileSynchronizer = null;
roslynSettingsFileSynchronizer?.Dispose();
roslynSettingsFileSynchronizer = null;
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SonarLint.VisualStudio.Roslyn.Suppressions.InProcess;
using static SonarLint.VisualStudio.Roslyn.Suppressions.UnitTests.TestHelper;

Expand All @@ -31,12 +29,13 @@ public class IssueConverterTests
[TestMethod]
public void Convert_SimplePropertiesAreHandledCorrectly()
{
var sonarIssue = CreateSonarQubeIssue(hash: "aaaa", filePath: "\\bbb\\ccc\\file.txt");
var sonarIssue = CreateSonarQubeIssue(hash: "aaaa", filePath: "\\bbb\\ccc\\file.txt", issueKey: "key");

var actual = RoslynSettingsFileSynchronizer.IssueConverter.Convert(sonarIssue);
var actual = IssueConverter.Convert(sonarIssue);

actual.Hash.Should().Be("aaaa");
actual.FilePath.Should().Be("\\bbb\\ccc\\file.txt");
actual.IssueServerKey.Should().Be("key");
}

[TestMethod]
Expand All @@ -48,9 +47,9 @@ public void Convert_LineNumbersAreHandledCorrectly(int? sonarLineNumber, int? ex
// 1-based Sonar line numbers should be converted to 0-based Roslyn line numbers
var sonarIssue = CreateSonarQubeIssue(line: sonarLineNumber);

var actual = RoslynSettingsFileSynchronizer.IssueConverter.Convert(sonarIssue);
var actual = IssueConverter.Convert(sonarIssue);

if(expected.HasValue)
if (expected.HasValue)
{
actual.RoslynIssueLine.Value.Should().Be(expected);
}
Expand Down Expand Up @@ -80,7 +79,7 @@ public void Convert_RepoKeysAreHandledCorrectly(string compositeKey, RoslynLangu
{
var sonarIssue = CreateSonarQubeIssue(ruleId: compositeKey);

var actual = RoslynSettingsFileSynchronizer.IssueConverter.Convert(sonarIssue);
var actual = IssueConverter.Convert(sonarIssue);

actual.RoslynLanguage.Should().Be(expectedLanguage);
actual.RoslynRuleId.Should().Be(expectedRuleKey);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/*
* SonarLint for Visual Studio
* Copyright (C) 2016-2025 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.Core;
using SonarLint.VisualStudio.Roslyn.Suppressions.InProcess;
using SonarLint.VisualStudio.Roslyn.Suppressions.SettingsFile;
using SonarQube.Client.Models;
using static SonarLint.VisualStudio.Roslyn.Suppressions.UnitTests.TestHelper;

namespace SonarLint.VisualStudio.Roslyn.Suppressions.UnitTests.InProcess;

[TestClass]
public class NewSuppressedIssuesCalculatorTests : SuppressedIssuesCalculatorTestsBase
{
[TestInitialize]
public void TestInitialize()
{
RoslynSettingsFileStorage = Substitute.For<IRoslynSettingsFileStorage>();
Logger = Substitute.For<ILogger>();
Logger.ForContext(Arg.Any<string[]>()).Returns(Logger);
}

[TestMethod]
public void CreateNewSuppressedIssuesCalculator_IssueDoNotExist_IssuesAreConvertedAndFiltered()
{
var testSubject = CreateNewSuppressedIssuesCalculator([
CsharpIssueSuppressed, // C# issue
VbNetIssueSuppressed, // VB issue
CppIssueSuppressed, // C++ issue - ignored
UnknownRepoIssue, // unrecognised repo - ignored
InvalidRepoKeyIssue, // invalid repo key - ignored
NoRuleIdIssue // invalid repo key (no rule id) - ignored
]);

var result = testSubject.GetSuppressedIssuesOrNull(RoslynSettingsKey);

VerifyExpectedSuppressions([.. result], [CsharpIssueSuppressed, VbNetIssueSuppressed]);
Logger.Received(1).LogVerbose(Resources.Strings.RoslynSettingsFileSynchronizerAddNewSuppressions);
}

[TestMethod]
public void CreateNewSuppressedIssuesCalculator_IssueDoNotExist_OnlySuppressedIssuesAreInSettings()
{
MockExistingSuppressionsOnSettingsFile();
var testSubject = CreateNewSuppressedIssuesCalculator([
CsharpIssueSuppressed,
VbNetIssueSuppressed,
CsharpIssueNotSuppressed,
VbNetIssueNotSuppressed,
]);

var result = testSubject.GetSuppressedIssuesOrNull(RoslynSettingsKey);

VerifyExpectedSuppressions([.. result], [CsharpIssueSuppressed, VbNetIssueSuppressed]);
Logger.Received(1).LogVerbose(Resources.Strings.RoslynSettingsFileSynchronizerAddNewSuppressions);
}

[TestMethod]
public void CreateNewSuppressedIssuesCalculator_IssuesExist_UpdatesCorrectly()
{
var newSonarQubeIssues = new[] { CsharpIssueSuppressed, VbNetIssueSuppressed };
MockExistingSuppressionsOnSettingsFile(newSonarQubeIssues);
var testSubject = CreateNewSuppressedIssuesCalculator(newSonarQubeIssues);

var result = testSubject.GetSuppressedIssuesOrNull(RoslynSettingsKey);

VerifyExpectedSuppressions([.. result], newSonarQubeIssues);
Logger.Received(1).LogVerbose(Resources.Strings.RoslynSettingsFileSynchronizerAddNewSuppressions);
}

[TestMethod]
public void CreateNewSuppressedIssuesCalculator_TwoNewIssuesAdded_DoesNotRemoveExistingOnes()
{
var newSonarQubeIssues = new[] { CreateSonarQubeIssue("csharpsquid:S666"), CreateSonarQubeIssue("vbnet:S666") };
var existingIssues = new[] { CsharpIssueSuppressed, VbNetIssueSuppressed, };
MockExistingSuppressionsOnSettingsFile(existingIssues);
var testSubject = CreateNewSuppressedIssuesCalculator(newSonarQubeIssues);

var result = testSubject.GetSuppressedIssuesOrNull(RoslynSettingsKey);

var expectedIssues = existingIssues.Union(newSonarQubeIssues).ToArray();
VerifyExpectedSuppressions([.. result], expectedIssues);
Logger.Received(1).LogVerbose(Resources.Strings.RoslynSettingsFileSynchronizerAddNewSuppressions);
}

private NewSuppressedIssuesCalculator CreateNewSuppressedIssuesCalculator(IEnumerable<SonarQubeIssue> sonarQubeIssues) => new(Logger, RoslynSettingsFileStorage, sonarQubeIssues);
}
Loading

0 comments on commit d2ae5c9

Please sign in to comment.