diff --git a/SonarLint.VisualStudio.Integration.sln.DotSettings b/SonarLint.VisualStudio.Integration.sln.DotSettings
index 5f03c02e1..cc8667465 100644
--- a/SonarLint.VisualStudio.Integration.sln.DotSettings
+++ b/SonarLint.VisualStudio.Integration.sln.DotSettings
@@ -132,4 +132,9 @@
False
False
True
- False
\ No newline at end of file
+ False
+ True
+ True
+ True
+ True
+ True
\ No newline at end of file
diff --git a/src/ConnectedMode.UnitTests/UI/ProgressReporterViewModelTests.cs b/src/ConnectedMode.UnitTests/UI/ProgressReporterViewModelTests.cs
index a815f1ea8..8e36c7a40 100644
--- a/src/ConnectedMode.UnitTests/UI/ProgressReporterViewModelTests.cs
+++ b/src/ConnectedMode.UnitTests/UI/ProgressReporterViewModelTests.cs
@@ -27,8 +27,8 @@ namespace SonarLint.VisualStudio.ConnectedMode.UnitTests.UI;
[TestClass]
public class ProgressReporterViewModelTests
{
- private ProgressReporterViewModel testSubject;
private ILogger logger;
+ private ProgressReporterViewModel testSubject;
[TestInitialize]
public void TestInitialize()
diff --git a/src/Education.UnitTests/EducationTests.cs b/src/Education.UnitTests/EducationTests.cs
index c049485d9..d7a452d2c 100644
--- a/src/Education.UnitTests/EducationTests.cs
+++ b/src/Education.UnitTests/EducationTests.cs
@@ -19,163 +19,145 @@
*/
using System.Windows.Documents;
-using Moq;
+using NSubstitute.ReturnsExtensions;
using SonarLint.VisualStudio.Core;
-using SonarLint.VisualStudio.Core.Suppressions;
using SonarLint.VisualStudio.Education.Rule;
using SonarLint.VisualStudio.Education.XamlGenerator;
using SonarLint.VisualStudio.TestInfrastructure;
-namespace SonarLint.VisualStudio.Education.UnitTests
+namespace SonarLint.VisualStudio.Education.UnitTests;
+
+[TestClass]
+public class EducationTests
{
- [TestClass]
- public class EducationTests
+ private readonly SonarCompositeRuleId knownRule = new("repoKey", "ruleKey");
+ private readonly SonarCompositeRuleId unknownRule = new("known", "xxx");
+
+ private ILogger logger;
+ private IRuleHelpToolWindow ruleDescriptionToolWindow;
+ private IRuleHelpXamlBuilder ruleHelpXamlBuilder;
+ private IRuleInfo ruleInfo;
+ private IRuleMetaDataProvider ruleMetadataProvider;
+ private IShowRuleInBrowser showRuleInBrowser;
+ private Education testSubject;
+ private IThreadHandling threadHandling;
+ private IToolWindowService toolWindowService;
+
+ [TestInitialize]
+ public void TestInitialize()
+ {
+ toolWindowService = Substitute.For();
+ ruleMetadataProvider = Substitute.For();
+ showRuleInBrowser = Substitute.For();
+ ruleHelpXamlBuilder = Substitute.For();
+ ruleDescriptionToolWindow = Substitute.For();
+ ruleInfo = Substitute.For();
+ logger = new TestLogger(true);
+ threadHandling = new NoOpThreadHandler();
+ SetupKnownRule();
+ SetupUnknownRule();
+
+ testSubject = new Education(toolWindowService, ruleMetadataProvider, showRuleInBrowser, logger, ruleHelpXamlBuilder, threadHandling);
+ }
+
+ [TestMethod]
+ public void MefCtor_CheckIsExported() =>
+ MefTestHelpers.CheckTypeCanBeImported(
+ MefTestHelpers.CreateExport(),
+ MefTestHelpers.CreateExport(),
+ MefTestHelpers.CreateExport(),
+ MefTestHelpers.CreateExport(),
+ MefTestHelpers.CreateExport());
+
+ [TestMethod]
+ public void Ctor_IsFreeThreaded()
+ {
+ toolWindowService.ReceivedCalls().Should().HaveCount(0);
+ ruleMetadataProvider.ReceivedCalls().Should().HaveCount(0);
+ showRuleInBrowser.ReceivedCalls().Should().HaveCount(0);
+ ruleHelpXamlBuilder.ReceivedCalls().Should().HaveCount(0);
+ }
+
+ [TestMethod]
+ public void ShowRuleHelp_KnownRule_DocumentIsDisplayedInToolWindow()
+ {
+ var flowDocument = MockFlowDocument();
+ toolWindowService.GetToolWindow().Returns(ruleDescriptionToolWindow);
+
+ testSubject.ShowRuleHelp(knownRule, null, null);
+
+ VerifyGetsRuleInfoForCorrectRuleId(knownRule);
+ VerifyRuleIsDisplayedInIde(flowDocument);
+ VerifyRuleNotShownInBrowser();
+ }
+
+ [TestMethod]
+ public void ShowRuleHelp_FailedToDisplayRule_RuleIsShownInBrowser()
+ {
+ ruleHelpXamlBuilder.When(x => x.Create(ruleInfo, /* todo by SLVS-1630 */ null)).Do(x => throw new Exception("some layout error"));
+
+ testSubject.ShowRuleHelp(knownRule, null, /* todo by SLVS-1630 */ null);
+
+ VerifyGetsRuleInfoForCorrectRuleId(knownRule);
+ VerifyRuleShownInBrowser(knownRule);
+ VerifyAttemptsToBuildRuleButFails();
+ }
+
+ [TestMethod]
+ public void ShowRuleHelp_UnknownRule_RuleIsShownInBrowser()
+ {
+ testSubject.ShowRuleHelp(unknownRule, null, /* todo by SLVS-1630 */ null);
+
+ VerifyGetsRuleInfoForCorrectRuleId(unknownRule);
+ VerifyRuleShownInBrowser(unknownRule);
+ VerifyNotAttemptsBuildRule();
+ }
+
+ [TestMethod]
+ public void ShowRuleHelp_FilterableIssueProvided_CallsGetRuleInfoForIssue()
+ {
+ var issueId = Guid.NewGuid();
+
+ testSubject.ShowRuleHelp(knownRule, issueId, null);
+
+ ruleMetadataProvider.Received(1).GetRuleInfoAsync(knownRule, issueId);
+ }
+
+ private void VerifyGetsRuleInfoForCorrectRuleId(SonarCompositeRuleId ruleId) => ruleMetadataProvider.Received(1).GetRuleInfoAsync(ruleId, Arg.Any());
+
+ private void VerifyRuleShownInBrowser(SonarCompositeRuleId ruleId) => showRuleInBrowser.Received(1).ShowRuleDescription(ruleId);
+
+ private void VerifyRuleNotShownInBrowser() => showRuleInBrowser.ReceivedCalls().Should().HaveCount(0);
+
+ private void VerifyToolWindowShown() => toolWindowService.Received(1).Show(RuleHelpToolWindow.ToolWindowId);
+
+ private void VerifyAttemptsToBuildRuleButFails()
{
- [TestMethod]
- public void MefCtor_CheckIsExported()
- {
- MefTestHelpers.CheckTypeCanBeImported(
- MefTestHelpers.CreateExport(),
- MefTestHelpers.CreateExport(),
- MefTestHelpers.CreateExport(),
- MefTestHelpers.CreateExport(),
- MefTestHelpers.CreateExport());
- }
+ ruleHelpXamlBuilder.ReceivedCalls().Should().HaveCount(1);
+ toolWindowService.ReceivedCalls().Should().HaveCount(1);
+ }
+
+ private void VerifyNotAttemptsBuildRule()
+ {
+ ruleHelpXamlBuilder.ReceivedCalls().Should().HaveCount(0);
+ toolWindowService.ReceivedCalls().Should().HaveCount(0);
+ }
+
+ private void VerifyRuleIsDisplayedInIde(FlowDocument flowDocument)
+ {
+ ruleHelpXamlBuilder.Received(1).Create(ruleInfo, /* todo by SLVS-1630 */ null);
+ ruleDescriptionToolWindow.Received(1).UpdateContent(flowDocument);
+ VerifyToolWindowShown();
+ }
+
+ private void SetupKnownRule() => ruleMetadataProvider.GetRuleInfoAsync(knownRule, Arg.Any()).Returns(ruleInfo);
- [TestMethod]
- public void ShowRuleHelp_KnownRule_DocumentIsDisplayedInToolWindow()
- {
- var ruleMetaDataProvider = new Mock();
- var ruleId = new SonarCompositeRuleId("repoKey", "ruleKey");
-
- var ruleInfo = Mock.Of();
- ruleMetaDataProvider.Setup(x => x.GetRuleInfoAsync(It.IsAny(), It.IsAny())).ReturnsAsync(ruleInfo);
-
- var flowDocument = Mock.Of();
- var ruleHelpXamlBuilder = new Mock();
- ruleHelpXamlBuilder.Setup(x => x.Create(ruleInfo, /* todo by SLVS-1630 */ null)).Returns(flowDocument);
-
- var ruleDescriptionToolWindow = new Mock();
-
- var toolWindowService = new Mock();
- toolWindowService.Setup(x => x.GetToolWindow()).Returns(ruleDescriptionToolWindow.Object);
-
- var showRuleInBrowser = new Mock();
- var testSubject = CreateEducation(toolWindowService.Object,
- ruleMetaDataProvider.Object,
- showRuleInBrowser.Object,
- ruleHelpXamlBuilder.Object);
-
- // Sanity check - tool window not yet fetched
- toolWindowService.Invocations.Should().HaveCount(0);
-
- // Act
- testSubject.ShowRuleHelp(ruleId, null, null);
-
- ruleMetaDataProvider.Verify(x => x.GetRuleInfoAsync(ruleId, It.IsAny()), Times.Once);
- ruleHelpXamlBuilder.Verify(x => x.Create(ruleInfo, /* todo by SLVS-1630 */ null), Times.Once);
- ruleDescriptionToolWindow.Verify(x => x.UpdateContent(flowDocument), Times.Once);
- toolWindowService.Verify(x => x.Show(RuleHelpToolWindow.ToolWindowId), Times.Once);
-
- showRuleInBrowser.Invocations.Should().HaveCount(0);
- }
-
- [TestMethod]
- public void ShowRuleHelp_FailedToDisplayRule_RuleIsShownInBrowser()
- {
- var toolWindowService = new Mock();
- var ruleMetadataProvider = new Mock();
- var ruleHelpXamlBuilder = new Mock();
- var showRuleInBrowser = new Mock();
-
- var ruleId = new SonarCompositeRuleId("repoKey", "ruleKey");
-
- var ruleInfo = Mock.Of();
- ruleMetadataProvider.Setup(x => x.GetRuleInfoAsync(It.IsAny(), It.IsAny())).ReturnsAsync(ruleInfo);
-
- ruleHelpXamlBuilder.Setup(x => x.Create(ruleInfo, /* todo by SLVS-1630 */ null)).Throws(new Exception("some layout error"));
-
- var testSubject = CreateEducation(
- toolWindowService.Object,
- ruleMetadataProvider.Object,
- showRuleInBrowser.Object,
- ruleHelpXamlBuilder.Object);
-
- toolWindowService.Reset(); // Called in the constructor, so need to reset to clear the list of invocations
-
- testSubject.ShowRuleHelp(ruleId, null, /* todo by SLVS-1630 */null);
-
- ruleMetadataProvider.Verify(x => x.GetRuleInfoAsync(ruleId, It.IsAny()), Times.Once);
- showRuleInBrowser.Verify(x => x.ShowRuleDescription(ruleId), Times.Once);
-
- // should have attempted to build the rule, but failed
- ruleHelpXamlBuilder.Invocations.Should().HaveCount(1);
- toolWindowService.Invocations.Should().HaveCount(1);
- }
-
- [TestMethod]
- public void ShowRuleHelp_UnknownRule_RuleIsShownInBrowser()
- {
- var toolWindowService = new Mock();
- var ruleMetadataProvider = new Mock();
- var ruleHelpXamlBuilder = new Mock();
- var showRuleInBrowser = new Mock();
-
- var unknownRule = new SonarCompositeRuleId("known", "xxx");
- ruleMetadataProvider.Setup(x => x.GetRuleInfoAsync(unknownRule, It.IsAny())).ReturnsAsync((IRuleInfo)null);
-
- var testSubject = CreateEducation(
- toolWindowService.Object,
- ruleMetadataProvider.Object,
- showRuleInBrowser.Object,
- ruleHelpXamlBuilder.Object);
-
- toolWindowService.Reset(); // Called in the constructor, so need to reset to clear the list of invocations
-
- testSubject.ShowRuleHelp(unknownRule, null, /* todo by SLVS-1630 */ null);
-
- ruleMetadataProvider.Verify(x => x.GetRuleInfoAsync(unknownRule, It.IsAny()), Times.Once);
- showRuleInBrowser.Verify(x => x.ShowRuleDescription(unknownRule), Times.Once);
-
- // Should not have attempted to build the rule
- ruleHelpXamlBuilder.Invocations.Should().HaveCount(0);
- toolWindowService.Invocations.Should().HaveCount(0);
- }
-
- [TestMethod]
- public void ShowRuleHelp_FilterableIssueProvided_CallsGetRuleInfoForIssue()
- {
- var toolWindowService = new Mock();
- var ruleMetadataProvider = new Mock();
- var ruleHelpXamlBuilder = new Mock();
- var showRuleInBrowser = new Mock();
- var issueId = Guid.NewGuid();
- var ruleId = new SonarCompositeRuleId("repoKey", "ruleKey");
- ruleMetadataProvider.Setup(x => x.GetRuleInfoAsync(ruleId, issueId)).ReturnsAsync((IRuleInfo)null);
- var testSubject = CreateEducation(
- toolWindowService.Object,
- ruleMetadataProvider.Object,
- showRuleInBrowser.Object,
- ruleHelpXamlBuilder.Object);
-
- testSubject.ShowRuleHelp(ruleId,issueId, null);
-
- ruleMetadataProvider.Verify(x => x.GetRuleInfoAsync(ruleId, issueId), Times.Once);
- }
-
- private Education CreateEducation(IToolWindowService toolWindowService = null,
- IRuleMetaDataProvider ruleMetadataProvider = null,
- IShowRuleInBrowser showRuleInBrowser = null,
- IRuleHelpXamlBuilder ruleHelpXamlBuilder = null)
- {
- toolWindowService ??= Mock.Of();
- ruleMetadataProvider ??= Mock.Of();
- showRuleInBrowser ??= Mock.Of();
- ruleHelpXamlBuilder ??= Mock.Of();
- var logger = new TestLogger(logToConsole: true);
- var threadHandling = new NoOpThreadHandler();
-
- return new Education(toolWindowService, ruleMetadataProvider, showRuleInBrowser, logger, ruleHelpXamlBuilder, threadHandling);
- }
+ private void SetupUnknownRule() => ruleMetadataProvider.GetRuleInfoAsync(unknownRule, Arg.Any()).ReturnsNull();
+
+ private FlowDocument MockFlowDocument()
+ {
+ var flowDocument = Substitute.For();
+ ruleHelpXamlBuilder.Create(ruleInfo, /* todo by SLVS-1630 */ null).Returns(flowDocument);
+ return flowDocument;
}
}
diff --git a/src/Education.UnitTests/ErrorList/SonarErrorListEventProcessorProviderTests.cs b/src/Education.UnitTests/ErrorList/SonarErrorListEventProcessorProviderTests.cs
index e6a761f54..75b6199b4 100644
--- a/src/Education.UnitTests/ErrorList/SonarErrorListEventProcessorProviderTests.cs
+++ b/src/Education.UnitTests/ErrorList/SonarErrorListEventProcessorProviderTests.cs
@@ -18,37 +18,31 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-using FluentAssertions;
using Microsoft.VisualStudio.Shell.TableControl;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using Moq;
using SonarLint.VisualStudio.Core;
-using SonarLint.VisualStudio.Education.SonarLint.VisualStudio.Education.ErrorList;
+using SonarLint.VisualStudio.Education.ErrorList;
using SonarLint.VisualStudio.Infrastructure.VS;
using SonarLint.VisualStudio.TestInfrastructure;
-namespace SonarLint.VisualStudio.Education.UnitTests.ErrorList
+namespace SonarLint.VisualStudio.Education.UnitTests.ErrorList;
+
+[TestClass]
+public class SonarErrorListEventProcessorProviderTests
{
- [TestClass]
- public class SonarErrorListEventProcessorProviderTests
- {
- [TestMethod]
- public void MefCtor_CheckIsExported()
- {
- MefTestHelpers.CheckTypeCanBeImported(
- MefTestHelpers.CreateExport(),
- MefTestHelpers.CreateExport(),
- MefTestHelpers.CreateExport());
- }
+ [TestMethod]
+ public void MefCtor_CheckIsExported() =>
+ MefTestHelpers.CheckTypeCanBeImported(
+ MefTestHelpers.CreateExport(),
+ MefTestHelpers.CreateExport(),
+ MefTestHelpers.CreateExport());
- [TestMethod]
- public void Get_CreatesAndReturnsProcessor()
- {
- var testSubject = new SonarErrorListEventProcessorProvider(Mock.Of(), Mock.Of(), Mock.Of());
+ [TestMethod]
+ public void Get_CreatesAndReturnsProcessor()
+ {
+ var testSubject = new SonarErrorListEventProcessorProvider(Substitute.For(), Substitute.For(), Substitute.For());
- var actual = testSubject.GetAssociatedEventProcessor(Mock.Of());
+ var actual = testSubject.GetAssociatedEventProcessor(Substitute.For());
- actual.Should().NotBeNull();
- }
+ actual.Should().NotBeNull();
}
}
diff --git a/src/Education.UnitTests/ErrorList/SonarErrorListEventProcessorTests.cs b/src/Education.UnitTests/ErrorList/SonarErrorListEventProcessorTests.cs
index 8ce2c980d..0ed066c36 100644
--- a/src/Education.UnitTests/ErrorList/SonarErrorListEventProcessorTests.cs
+++ b/src/Education.UnitTests/ErrorList/SonarErrorListEventProcessorTests.cs
@@ -19,95 +19,97 @@
*/
using Microsoft.VisualStudio.Shell.TableControl;
-using Moq;
using SonarLint.VisualStudio.Core;
using SonarLint.VisualStudio.Core.Suppressions;
-using SonarLint.VisualStudio.Education.SonarLint.VisualStudio.Education.ErrorList;
+using SonarLint.VisualStudio.Education.ErrorList;
using SonarLint.VisualStudio.Infrastructure.VS;
using SonarLint.VisualStudio.TestInfrastructure;
-namespace SonarLint.VisualStudio.Education.UnitTests.ErrorList
+namespace SonarLint.VisualStudio.Education.UnitTests.ErrorList;
+
+[TestClass]
+public class SonarErrorListEventProcessorTests
{
- [TestClass]
- public class SonarErrorListEventProcessorTests
+ private readonly TableEntryEventArgs eventArgs = new();
+
+ private IEducation education;
+ private IErrorListHelper errorListHelper;
+ private IFilterableIssue filterableIssue;
+ private ITableEntryHandle handle;
+ private ILogger logger;
+ private SonarErrorListEventProcessor testSubject;
+
+ [TestInitialize]
+ public void TestInitialize()
{
- [TestMethod]
- public void PreprocessNavigateToHelp_NotASonarRule_EventIsNotHandled()
- {
- SonarCompositeRuleId ruleId = null;
- var handle = Mock.Of();
- var errorListHelper = CreateErrorListHelper(isSonarRule: false, ruleId);
+ education = Substitute.For();
+ errorListHelper = Substitute.For();
+ handle = Substitute.For();
+ filterableIssue = Substitute.For();
+ logger = new TestLogger();
- var education = new Mock();
- var eventArgs = new TableEntryEventArgs();
+ testSubject = new SonarErrorListEventProcessor(education, errorListHelper, logger);
+ }
- var testSubject = CreateTestSubject(education.Object, errorListHelper.Object);
+ [TestMethod]
+ public void PreprocessNavigateToHelp_NotASonarRule_EventIsNotHandled()
+ {
+ SonarCompositeRuleId ruleId = null;
+ MockErrorListHelper(false, ruleId);
- testSubject.PreprocessNavigateToHelp(handle, eventArgs);
+ testSubject.PreprocessNavigateToHelp(handle, eventArgs);
- errorListHelper.Verify(x => x.TryGetRuleId(handle, out ruleId));
- education.Invocations.Should().HaveCount(0);
- eventArgs.Handled.Should().BeFalse();
- }
+ errorListHelper.Received(1).TryGetRuleId(handle, out _);
+ education.ReceivedCalls().Should().HaveCount(0);
+ eventArgs.Handled.Should().BeFalse();
+ }
- [TestMethod]
- public void PreprocessNavigateToHelp_IsASonarRule_EventIsHandledAndEducationServiceCalled()
- {
- SonarCompositeRuleId ruleId;
- SonarCompositeRuleId.TryParse("cpp:S123", out ruleId);
- var handle = Mock.Of();
- var errorListHelper = CreateErrorListHelper(isSonarRule: true, ruleId);
+ [TestMethod]
+ public void PreprocessNavigateToHelp_IsASonarRule_EventIsHandledAndEducationServiceCalled()
+ {
+ var ruleId = CreateSonarCompositeRuleId("cpp:S123");
+ MockErrorListHelper(true, ruleId);
- var education = new Mock();
- var eventArgs = new TableEntryEventArgs();
+ testSubject.PreprocessNavigateToHelp(handle, eventArgs);
- var testSubject = CreateTestSubject(education.Object, errorListHelper.Object);
+ errorListHelper.Received(1).TryGetRuleId(handle, out _);
+ education.ReceivedCalls().Should().HaveCount(1);
+ education.Received(1).ShowRuleHelp(ruleId, null, /* todo by SLVS-1630 */ null);
+ eventArgs.Handled.Should().BeTrue();
+ }
- testSubject.PreprocessNavigateToHelp(handle, eventArgs);
+ [TestMethod]
+ [DataRow(true)]
+ [DataRow(false)]
+ public void PreprocessNavigateToHelp_IsASonarRule_EducationServiceIsCalledWithIssueId(bool getFilterableIssueResult)
+ {
+ var ruleId = CreateSonarCompositeRuleId("cpp:S123");
+ MockErrorListHelper(true, ruleId);
+ MockGetFilterableIssue(getFilterableIssueResult);
- errorListHelper.Verify(x => x.TryGetRuleId(handle, out ruleId));
- education.Invocations.Should().HaveCount(1);
- education.Verify(x => x.ShowRuleHelp(ruleId, null, /* todo by SLVS-1630 */ null));
- eventArgs.Handled.Should().BeTrue();
- }
+ testSubject.PreprocessNavigateToHelp(handle, new TableEntryEventArgs());
- [TestMethod]
- [DataRow(true)]
- [DataRow(false)]
- public void PreprocessNavigateToHelp_IsASonarRule_EducationServiceIsCalledWithIssueId(bool getFilterableIssueResult)
- {
- SonarCompositeRuleId ruleId;
- IFilterableIssue filterableIssue = new Mock().Object;
- SonarCompositeRuleId.TryParse("cpp:S123", out ruleId);
- var handle = Mock.Of();
- var errorListHelper = CreateErrorListHelper(isSonarRule: true, ruleId);
- errorListHelper.Setup(x => x.TryGetFilterableIssue(It.IsAny(), out filterableIssue)).Returns(getFilterableIssueResult);
- var education = new Mock();
- var testSubject = CreateTestSubject(education.Object, errorListHelper.Object);
-
- testSubject.PreprocessNavigateToHelp(handle, new TableEntryEventArgs());
-
- education.Invocations.Should().HaveCount(1);
- education.Verify(x => x.ShowRuleHelp(ruleId, filterableIssue.IssueId, null));
- }
-
- private static Mock CreateErrorListHelper(bool isSonarRule, SonarCompositeRuleId ruleId)
+ education.ReceivedCalls().Should().HaveCount(1);
+ education.Received(1).ShowRuleHelp(ruleId, filterableIssue.IssueId, null);
+ }
+
+ private void MockGetFilterableIssue(bool getFilterableIssueResult) =>
+ errorListHelper.TryGetFilterableIssue(Arg.Any(), out _).Returns(callInfo =>
{
- var mock = new Mock();
- mock.Setup(x => x.TryGetRuleId(It.IsAny(), out ruleId)).Returns(isSonarRule);
- return mock;
- }
-
- private static SonarErrorListEventProcessor CreateTestSubject(IEducation educationService = null,
- IErrorListHelper errorListHelper = null,
- ILogger logger = null)
+ callInfo[1] = filterableIssue;
+ return getFilterableIssueResult;
+ });
+
+ private void MockErrorListHelper(bool isSonarRule, SonarCompositeRuleId ruleId) =>
+ errorListHelper.TryGetRuleId(Arg.Any(), out _).Returns(callInfo =>
{
- educationService ??= Mock.Of();
- errorListHelper ??= Mock.Of();
- logger ??= new TestLogger(logToConsole: true);
+ callInfo[1] = ruleId;
+ return isSonarRule;
+ });
- var testSubject = new SonarErrorListEventProcessor(educationService, errorListHelper, logger);
- return testSubject;
- }
+ private static SonarCompositeRuleId CreateSonarCompositeRuleId(string errorListErrorCode)
+ {
+ SonarCompositeRuleId.TryParse(errorListErrorCode, out var ruleId);
+ return ruleId;
}
}
diff --git a/src/Education.UnitTests/Rule/SLCoreRuleMetaDataProviderTests.cs b/src/Education.UnitTests/Rule/SLCoreRuleMetaDataProviderTests.cs
index 676b13904..8e770ee2a 100644
--- a/src/Education.UnitTests/Rule/SLCoreRuleMetaDataProviderTests.cs
+++ b/src/Education.UnitTests/Rule/SLCoreRuleMetaDataProviderTests.cs
@@ -18,24 +18,50 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-using Moq;
+using NSubstitute.ExceptionExtensions;
using SonarLint.VisualStudio.Core;
using SonarLint.VisualStudio.Education.Rule;
using SonarLint.VisualStudio.SLCore.Core;
-using SonarLint.VisualStudio.SLCore.Protocol;
+using SonarLint.VisualStudio.SLCore.Service.Issue;
+using SonarLint.VisualStudio.SLCore.Service.Issue.Models;
using SonarLint.VisualStudio.SLCore.Service.Rules;
using SonarLint.VisualStudio.SLCore.Service.Rules.Models;
using SonarLint.VisualStudio.SLCore.State;
using SonarLint.VisualStudio.TestInfrastructure;
-using SonarLint.VisualStudio.SLCore.Service.Issue;
-using SonarLint.VisualStudio.SLCore.Service.Issue.Models;
namespace SonarLint.VisualStudio.Education.UnitTests.Rule;
[TestClass]
public class SLCoreRuleMetaDataProviderTests
{
- private static readonly SonarCompositeRuleId CompositeRuleId = new("rule", "key1");
+ private readonly SonarCompositeRuleId compositeRuleId = new("rule", "key1");
+ private readonly ConfigurationScope configurationScope = new("id");
+ private readonly RuleInfo defaultRuleInfo = new(default, default, default, default, default, default, default, default);
+ private readonly EffectiveIssueDetailsDto effectiveIssueDetailsDto = new(default, default, default, default, default, default, default, default);
+ private readonly string errorMessage = "my message";
+ private readonly Guid issueId = Guid.NewGuid();
+
+ private IActiveConfigScopeTracker configScopeTrackerMock;
+ private IIssueSLCoreService issueServiceMock;
+ private TestLogger logger;
+ private IRuleInfoConverter ruleInfoConverter;
+ private IRulesSLCoreService rulesServiceMock;
+ private ISLCoreServiceProvider serviceProviderMock;
+ private SLCoreRuleMetaDataProvider testSubject;
+
+ [TestInitialize]
+ public void TestInitialize()
+ {
+ serviceProviderMock = Substitute.For();
+ configScopeTrackerMock = Substitute.For();
+ issueServiceMock = Substitute.For();
+ rulesServiceMock = Substitute.For();
+ ruleInfoConverter = Substitute.For();
+ logger = new TestLogger();
+
+ testSubject = new SLCoreRuleMetaDataProvider(serviceProviderMock, configScopeTrackerMock, ruleInfoConverter, logger);
+ MockupServices();
+ }
[TestMethod]
public void MefCtor_CheckIsExported() =>
@@ -51,12 +77,9 @@ public void MefCtor_CheckIsExported() =>
[TestMethod]
public async Task GetRuleInfoAsync_NoActiveScope_ReturnsNull()
{
- var testSubject =
- CreateTestSubject(out var serviceProviderMock, out var configScopeTrackerMock, out var logger);
- SetUpServiceProvider(serviceProviderMock, out _);
- SetUpConfigScopeTracker(configScopeTrackerMock, null);
+ SetUpConfigScopeTracker(null);
- var ruleInfo = await testSubject.GetRuleInfoAsync(CompositeRuleId);
+ var ruleInfo = await testSubject.GetRuleInfoAsync(compositeRuleId);
ruleInfo.Should().BeNull();
logger.AssertNoOutputMessages();
@@ -65,10 +88,9 @@ public async Task GetRuleInfoAsync_NoActiveScope_ReturnsNull()
[TestMethod]
public async Task GetRuleInfoAsync_ServiceUnavailable_ReturnsNull()
{
- var testSubject = CreateTestSubject(out _, out var configScopeTrackerMock, out var logger);
- SetUpConfigScopeTracker(configScopeTrackerMock, new ConfigurationScope("id"));
+ SetUpRuleServiceProvider(false);
- var ruleInfo = await testSubject.GetRuleInfoAsync(CompositeRuleId);
+ var ruleInfo = await testSubject.GetRuleInfoAsync(compositeRuleId);
ruleInfo.Should().BeNull();
logger.AssertNoOutputMessages();
@@ -77,209 +99,136 @@ public async Task GetRuleInfoAsync_ServiceUnavailable_ReturnsNull()
[TestMethod]
public void GetRuleInfoAsync_ServiceThrows_ReturnsNullAndLogs()
{
- var testSubject =
- CreateTestSubject(out var serviceProviderMock, out var configScopeTrackerMock, out var logger);
- SetUpConfigScopeTracker(configScopeTrackerMock, new ConfigurationScope("id"));
- SetUpServiceProvider(serviceProviderMock, out var rulesServiceMock);
- rulesServiceMock
- .Setup(x => x.GetEffectiveRuleDetailsAsync(It.IsAny()))
- .ThrowsAsync(new Exception("my message"));
+ MockGetEffectiveRuleDetailsAsyncThrows();
- var act = () => testSubject.GetRuleInfoAsync(CompositeRuleId);
+ var act = () => testSubject.GetRuleInfoAsync(compositeRuleId);
act.Should().NotThrow();
- logger.AssertPartialOutputStringExists("my message");
+ logger.AssertPartialOutputStringExists(errorMessage);
}
[TestMethod]
public async Task GetRuleInfoAsync_ForIssue_NoActiveScope_ReturnsNull()
{
- var testSubject =
- CreateTestSubject(out var serviceProviderMock, out var configScopeTrackerMock, out var logger);
- SetUpIssueServiceProvider(serviceProviderMock, out _);
- SetUpConfigScopeTracker(configScopeTrackerMock, null);
- var issueId = Guid.NewGuid();
+ SetUpConfigScopeTracker(null);
- var ruleInfo = await testSubject.GetRuleInfoAsync(default,issueId);
+ var ruleInfo = await testSubject.GetRuleInfoAsync(compositeRuleId, issueId);
ruleInfo.Should().BeNull();
logger.AssertNoOutputMessages();
}
[TestMethod]
- public async Task GetRuleInfoAsync_ForIssue_ServiceUnavailable_ReturnsNull()
+ public async Task GetRuleInfoAsync_ForIssue_IssueServiceUnavailable_ReturnsResultFromRulesService()
{
- var testSubject = CreateTestSubject(out _, out var configScopeTrackerMock, out var logger);
- SetUpConfigScopeTracker(configScopeTrackerMock, new ConfigurationScope("id"));
+ SetUpIssueServiceProvider(false);
+ MockGetEffectiveRuleDetailsAsync(compositeRuleId.ToString(), configurationScope.Id);
- var ruleInfo = await testSubject.GetRuleInfoAsync(default,Guid.NewGuid());
+ var ruleInfo = await testSubject.GetRuleInfoAsync(compositeRuleId, issueId);
- ruleInfo.Should().BeNull();
+ ruleInfo.Should().NotBeNull();
logger.AssertNoOutputMessages();
+ VerifyGetRuleDetailsWasCalled(compositeRuleId.ToString());
}
[TestMethod]
- public void GetRuleInfoAsync_ForIssue_ServiceThrows_ReturnsNullAndLogs()
+ public void GetRuleInfoAsync_ForIssue_IssueServiceThrows_ReturnsNullAndLogs()
{
- var testSubject =
- CreateTestSubject(out var serviceProviderMock, out var configScopeTrackerMock, out var logger);
- SetUpConfigScopeTracker(configScopeTrackerMock, new ConfigurationScope("id"));
- SetUpIssueServiceProvider(serviceProviderMock, out var issueServiceMock);
- issueServiceMock
- .Setup(x => x.GetEffectiveIssueDetailsAsync(It.IsAny()))
- .ThrowsAsync(new Exception("my message"));
+ MockGetEffectiveIssueDetailsAsyncThrows();
- var act = () => testSubject.GetRuleInfoAsync(default,Guid.NewGuid());
+ var act = () => testSubject.GetRuleInfoAsync(compositeRuleId, issueId);
act.Should().NotThrow();
- logger.AssertPartialOutputStringExists("my message");
+ logger.AssertPartialOutputStringExists(errorMessage);
}
[TestMethod]
- public async Task GetRuleInfoAsync_FilterableIssueNull_CallsGetEffectiveRuleDetailsAsync()
+ public async Task GetRuleInfoAsync_IssueIdNull_CallsGetEffectiveRuleDetailsAsync()
{
- var testSubject =
- CreateTestSubject(out var serviceProviderMock, out var configScopeTrackerMock, out _);
- SetUpIssueServiceProvider(serviceProviderMock, out var issueServiceMock);
- SetUpServiceProvider(serviceProviderMock, out var rulesServiceMock);
- SetUpConfigScopeTracker(configScopeTrackerMock, new ConfigurationScope("configscope"));
-
- await testSubject.GetRuleInfoAsync(CompositeRuleId, null);
+ await testSubject.GetRuleInfoAsync(compositeRuleId, null);
- rulesServiceMock.Verify(x => x.GetEffectiveRuleDetailsAsync(It.Is(p => p.ruleKey == CompositeRuleId.ToString())), Times.Once);
- issueServiceMock.Verify(x => x.GetEffectiveIssueDetailsAsync(It.IsAny()), Times.Never);
+ VerifyGetRuleDetailsWasCalled(compositeRuleId.ToString());
+ VerifyIssueDetailsWasNotCalled();
}
[TestMethod]
- public async Task GetRuleInfoAsync_FilterableIssueIdNull_CallsGetEffectiveRuleDetailsAsync()
+ public async Task GetRuleInfoAsync_IssueIdNotNull_CallsGetEffectiveIssueDetailsAsync()
{
- var testSubject =
- CreateTestSubject(out var serviceProviderMock, out var configScopeTrackerMock, out _);
- SetUpIssueServiceProvider(serviceProviderMock, out var issueServiceMock);
- SetUpServiceProvider(serviceProviderMock, out var rulesServiceMock);
- SetUpConfigScopeTracker(configScopeTrackerMock, new ConfigurationScope("configscope"));
- Guid? issueId = null;
+ MockGetEffectiveIssueDetailsAsync(issueId, configurationScope.Id);
- await testSubject.GetRuleInfoAsync(CompositeRuleId, issueId);
-
- rulesServiceMock.Verify(x => x.GetEffectiveRuleDetailsAsync(It.Is(p => p.ruleKey == CompositeRuleId.ToString())), Times.Once);
- issueServiceMock.Verify(x => x.GetEffectiveIssueDetailsAsync(It.IsAny()), Times.Never);
- }
+ await testSubject.GetRuleInfoAsync(compositeRuleId, issueId);
- [TestMethod]
- public async Task GetRuleInfoAsync_FilterableIssueIdNotNull_CallsGetEffectiveIssueDetailsAsync()
- {
- var configScopeId = "configscope";
- var issueId = Guid.NewGuid();
- var testSubject = CreateTestSubject(out var serviceProviderMock, out var configScopeTrackerMock, out _);
- SetUpIssueServiceProvider(serviceProviderMock, out var issueServiceMock);
- SetUpServiceProvider(serviceProviderMock, out var rulesServiceMock);
- SetUpConfigScopeTracker(configScopeTrackerMock, new ConfigurationScope(configScopeId));
- SetupIssuesService(issueServiceMock, issueId, configScopeId, CreateEffectiveIssueDetailsDto(new MQRModeDetails(default, default)));
-
- await testSubject.GetRuleInfoAsync(CompositeRuleId, issueId);
-
- rulesServiceMock.Verify(x => x.GetEffectiveRuleDetailsAsync(It.IsAny()), Times.Never);
- issueServiceMock.Verify(x => x.GetEffectiveIssueDetailsAsync(It.Is(p => p.issueId == issueId)), Times.Once);
+ VerifyRuleDetailsWasNotCalled();
+ VerifyGetIssueDetailsWasCalled(issueId);
}
[TestMethod]
public async Task GetRuleInfoAsync_GetEffectiveIssueDetailsAsyncThrows_CallsGetEffectiveRuleDetailsAsync()
{
- var testSubject =
- CreateTestSubject(out var serviceProviderMock, out var configScopeTrackerMock, out _);
- SetUpIssueServiceProvider(serviceProviderMock, out var issueServiceMock);
- SetUpServiceProvider(serviceProviderMock, out var rulesServiceMock);
- SetUpConfigScopeTracker(configScopeTrackerMock, new ConfigurationScope("configscope"));
- var issueId = Guid.NewGuid();
- issueServiceMock
- .Setup(x => x.GetEffectiveIssueDetailsAsync(It.IsAny()))
- .ThrowsAsync(new Exception("my message"));
-
- await testSubject.GetRuleInfoAsync(CompositeRuleId, issueId);
-
- rulesServiceMock.Verify(x => x.GetEffectiveRuleDetailsAsync(It.Is(p => p.ruleKey == CompositeRuleId.ToString())), Times.Once);
- issueServiceMock.Verify(x => x.GetEffectiveIssueDetailsAsync(It.Is(p => p.issueId == issueId)), Times.Once);
+ MockGetEffectiveIssueDetailsAsyncThrows();
+
+ await testSubject.GetRuleInfoAsync(compositeRuleId, issueId);
+
+ VerifyGetRuleDetailsWasCalled(compositeRuleId.ToString());
+ VerifyGetIssueDetailsWasCalled(issueId);
}
[TestMethod]
public async Task GetRuleInfoAsync_BothServicesThrow_ReturnsNull()
{
- var testSubject =
- CreateTestSubject(out var serviceProviderMock, out var configScopeTrackerMock, out _);
- SetUpIssueServiceProvider(serviceProviderMock, out var issueServiceMock);
- SetUpServiceProvider(serviceProviderMock, out var rulesServiceMock);
- SetUpConfigScopeTracker(configScopeTrackerMock, new ConfigurationScope("configscope"));
- var issueId = Guid.NewGuid();
- issueServiceMock
- .Setup(x => x.GetEffectiveIssueDetailsAsync(It.IsAny()))
- .ThrowsAsync(new Exception("my message"));
- rulesServiceMock
- .Setup(x => x.GetEffectiveRuleDetailsAsync(It.IsAny()))
- .ThrowsAsync(new Exception("my message"));
-
- var result = await testSubject.GetRuleInfoAsync(CompositeRuleId, issueId);
+ MockGetEffectiveIssueDetailsAsyncThrows();
+ MockGetEffectiveRuleDetailsAsyncThrows();
+
+ var result = await testSubject.GetRuleInfoAsync(compositeRuleId, issueId);
result.Should().BeNull();
- rulesServiceMock.Verify(x => x.GetEffectiveRuleDetailsAsync(It.Is(p => p.ruleKey == CompositeRuleId.ToString())), Times.Once);
- issueServiceMock.Verify(x => x.GetEffectiveIssueDetailsAsync(It.Is(p => p.issueId == issueId)), Times.Once);
+ VerifyGetRuleDetailsWasCalled(compositeRuleId.ToString());
+ VerifyGetIssueDetailsWasCalled(issueId);
}
- private static void SetUpConfigScopeTracker(
- Mock configScopeTrackerMock,
- ConfigurationScope scope) =>
- configScopeTrackerMock.SetupGet(x => x.Current).Returns(scope);
-
- private static void SetupIssuesService(
- Mock issuesServiceMock,
- Guid id,
- string configScopeId,
- EffectiveIssueDetailsDto response) =>
- issuesServiceMock
- .Setup(r => r.GetEffectiveIssueDetailsAsync(It.Is(p => p.configurationScopeId == configScopeId && p.issueId == id)))
- .ReturnsAsync(new GetEffectiveIssueDetailsResponse(response));
-
- private static void SetUpServiceProvider(
- Mock serviceProviderMock,
- out Mock rulesServiceMock)
- {
- rulesServiceMock = new Mock();
- var rulesService = rulesServiceMock.Object;
- serviceProviderMock.Setup(x => x.TryGetTransientService(out rulesService)).Returns(true);
- }
+ private void SetUpConfigScopeTracker(ConfigurationScope scope) => configScopeTrackerMock.Current.Returns(scope);
- private static void SetUpIssueServiceProvider(
- Mock serviceProviderMock,
- out Mock rulesServiceMock)
- {
- rulesServiceMock = new Mock();
- var rulesService = rulesServiceMock.Object;
- serviceProviderMock.Setup(x => x.TryGetTransientService(out rulesService)).Returns(true);
- }
+ private void MockGetEffectiveIssueDetailsAsyncThrows() => issueServiceMock.GetEffectiveIssueDetailsAsync(Arg.Any()).ThrowsAsync(new Exception(errorMessage));
+
+ private void MockGetEffectiveRuleDetailsAsyncThrows() => rulesServiceMock.GetEffectiveRuleDetailsAsync(Arg.Any()).ThrowsAsync(new Exception(errorMessage));
+
+ private void MockGetEffectiveIssueDetailsAsync(Guid id, string configScopeId) =>
+ issueServiceMock.GetEffectiveIssueDetailsAsync(Arg.Is(x => x.configurationScopeId == configScopeId && x.issueId == id))
+ .Returns(new GetEffectiveIssueDetailsResponse(effectiveIssueDetailsDto));
+
+ private void MockGetEffectiveRuleDetailsAsync(string ruleKey, string configScopeId) =>
+ rulesServiceMock.GetEffectiveRuleDetailsAsync(Arg.Is(x => x.configurationScopeId == configScopeId && x.ruleKey == ruleKey))
+ .Returns(new GetEffectiveRuleDetailsResponse(default));
- private static SLCoreRuleMetaDataProvider CreateTestSubject(
- out Mock serviceProviderMock,
- out Mock configScopeTrackerMock,
- out TestLogger logger)
+ private void SetUpRuleServiceProvider(bool result) =>
+ serviceProviderMock.TryGetTransientService(out Arg.Any()).Returns(callInfo =>
+ {
+ callInfo[0] = rulesServiceMock;
+ return result;
+ });
+
+ private void SetUpIssueServiceProvider(bool result) =>
+ serviceProviderMock.TryGetTransientService(out Arg.Any()).Returns(callInfo =>
+ {
+ callInfo[0] = issueServiceMock;
+ return result;
+ });
+
+ private void MockupServices()
{
- serviceProviderMock = new Mock();
- configScopeTrackerMock = new Mock();
- configScopeTrackerMock = new Mock();
- var ruleInfoConverter = new Mock();
- ruleInfoConverter.Setup(x => x.Convert(It.IsAny())).Returns(new RuleInfo(default, default, default, default, default, default, default, default));
- logger = new TestLogger();
- return new SLCoreRuleMetaDataProvider(serviceProviderMock.Object, configScopeTrackerMock.Object, ruleInfoConverter.Object, logger);
+ MockRuleInfoConverter();
+ SetUpIssueServiceProvider(true);
+ SetUpRuleServiceProvider(true);
+ SetUpConfigScopeTracker(configurationScope);
}
- private static EffectiveIssueDetailsDto CreateEffectiveIssueDetailsDto(Either severityDetails,
- Either description = default) =>
- new(
- default,
- default,
- default,
- default,
- description,
- default,
- severityDetails,
- default);
+ private void MockRuleInfoConverter() => ruleInfoConverter.Convert(Arg.Any()).Returns(defaultRuleInfo);
+
+ private void VerifyGetIssueDetailsWasCalled(Guid id) => issueServiceMock.Received(1).GetEffectiveIssueDetailsAsync(Arg.Is(x => x.issueId == id));
+
+ private void VerifyGetRuleDetailsWasCalled(string ruleKey) => rulesServiceMock.Received(1).GetEffectiveRuleDetailsAsync(Arg.Is(x => x.ruleKey == ruleKey));
+
+ private void VerifyIssueDetailsWasNotCalled() => issueServiceMock.DidNotReceive().GetEffectiveIssueDetailsAsync(Arg.Any());
+
+ private void VerifyRuleDetailsWasNotCalled() => rulesServiceMock.DidNotReceive().GetEffectiveRuleDetailsAsync(Arg.Any());
}
diff --git a/src/Education/Education.cs b/src/Education/Education.cs
index c2bb19d40..8e2737615 100644
--- a/src/Education/Education.cs
+++ b/src/Education/Education.cs
@@ -21,97 +21,96 @@
using System.ComponentModel.Composition;
using Microsoft.VisualStudio.Threading;
using SonarLint.VisualStudio.Core;
-using SonarLint.VisualStudio.Core.Suppressions;
using SonarLint.VisualStudio.Education.Rule;
using SonarLint.VisualStudio.Education.XamlGenerator;
using SonarLint.VisualStudio.Infrastructure.VS;
-namespace SonarLint.VisualStudio.Education
-{
- [Export(typeof(IEducation))]
- [PartCreationPolicy(CreationPolicy.Shared)]
- internal class Education : IEducation
- {
- private readonly IToolWindowService toolWindowService;
- private readonly IRuleMetaDataProvider ruleMetadataProvider;
- private readonly IRuleHelpXamlBuilder ruleHelpXamlBuilder;
- private readonly IShowRuleInBrowser showRuleInBrowser;
- private readonly ILogger logger;
- private readonly IThreadHandling threadHandling;
+namespace SonarLint.VisualStudio.Education;
- private IRuleHelpToolWindow ruleHelpToolWindow;
+[Export(typeof(IEducation))]
+[PartCreationPolicy(CreationPolicy.Shared)]
+internal class Education : IEducation
+{
+ private readonly ILogger logger;
+ private readonly IRuleHelpXamlBuilder ruleHelpXamlBuilder;
+ private readonly IRuleMetaDataProvider ruleMetadataProvider;
+ private readonly IShowRuleInBrowser showRuleInBrowser;
+ private readonly IThreadHandling threadHandling;
+ private readonly IToolWindowService toolWindowService;
- [ImportingConstructor]
- public Education(IToolWindowService toolWindowService, IRuleMetaDataProvider ruleMetadataProvider, IShowRuleInBrowser showRuleInBrowser, ILogger logger, IRuleHelpXamlBuilder ruleHelpXamlBuilder)
- : this(toolWindowService,
- ruleMetadataProvider,
- showRuleInBrowser,
- logger,
- ruleHelpXamlBuilder,
- ThreadHandling.Instance) { }
+ private IRuleHelpToolWindow ruleHelpToolWindow;
- internal /* for testing */ Education(IToolWindowService toolWindowService,
- IRuleMetaDataProvider ruleMetadataProvider,
- IShowRuleInBrowser showRuleInBrowser,
- ILogger logger,
- IRuleHelpXamlBuilder ruleHelpXamlBuilder,
- IThreadHandling threadHandling)
- {
- this.toolWindowService = toolWindowService;
- this.ruleHelpXamlBuilder = ruleHelpXamlBuilder;
- this.ruleMetadataProvider = ruleMetadataProvider;
- this.showRuleInBrowser = showRuleInBrowser;
- this.logger = logger;
- this.threadHandling = threadHandling;
- }
+ [ImportingConstructor]
+ public Education(
+ IToolWindowService toolWindowService,
+ IRuleMetaDataProvider ruleMetadataProvider,
+ IShowRuleInBrowser showRuleInBrowser,
+ ILogger logger,
+ IRuleHelpXamlBuilder ruleHelpXamlBuilder)
+ : this(toolWindowService,
+ ruleMetadataProvider,
+ showRuleInBrowser,
+ logger,
+ ruleHelpXamlBuilder,
+ ThreadHandling.Instance)
+ {
+ }
- public void ShowRuleHelp(SonarCompositeRuleId ruleId, Guid? issueId, string issueContext)
- {
- ShowRuleHelpAsync(ruleId, issueId, issueContext).Forget();
- }
+ internal /* for testing */ Education(
+ IToolWindowService toolWindowService,
+ IRuleMetaDataProvider ruleMetadataProvider,
+ IShowRuleInBrowser showRuleInBrowser,
+ ILogger logger,
+ IRuleHelpXamlBuilder ruleHelpXamlBuilder,
+ IThreadHandling threadHandling)
+ {
+ this.toolWindowService = toolWindowService;
+ this.ruleHelpXamlBuilder = ruleHelpXamlBuilder;
+ this.ruleMetadataProvider = ruleMetadataProvider;
+ this.showRuleInBrowser = showRuleInBrowser;
+ this.logger = logger;
+ this.threadHandling = threadHandling;
+ }
- private async Task ShowRuleHelpAsync(SonarCompositeRuleId ruleId, Guid? issueId, string issueContext)
- {
- await threadHandling.SwitchToBackgroundThread();
+ public void ShowRuleHelp(SonarCompositeRuleId ruleId, Guid? issueId, string issueContext) => ShowRuleHelpAsync(ruleId, issueId, issueContext).Forget();
- var ruleInfo = await ruleMetadataProvider.GetRuleInfoAsync(ruleId, issueId);
+ private async Task ShowRuleHelpAsync(SonarCompositeRuleId ruleId, Guid? issueId, string issueContext)
+ {
+ await threadHandling.SwitchToBackgroundThread();
- await threadHandling.RunOnUIThreadAsync(() =>
- {
- if (ruleInfo == null)
- {
- showRuleInBrowser.ShowRuleDescription(ruleId);
- }
- else
- {
- ShowRuleInIde(ruleInfo, ruleId, issueContext);
- }
- });
- }
+ var ruleInfo = await ruleMetadataProvider.GetRuleInfoAsync(ruleId, issueId);
- private void ShowRuleInIde(IRuleInfo ruleInfo, SonarCompositeRuleId ruleId, string issueContext)
+ await threadHandling.RunOnUIThreadAsync(() =>
{
- threadHandling.ThrowIfNotOnUIThread();
-
- // Lazily fetch the tool window from a UI thread
- if (ruleHelpToolWindow == null)
+ if (ruleInfo == null)
{
- ruleHelpToolWindow = toolWindowService.GetToolWindow();
+ showRuleInBrowser.ShowRuleDescription(ruleId);
}
-
- try
+ else
{
- var flowDocument = ruleHelpXamlBuilder.Create(ruleInfo, issueContext);
+ ShowRuleInIde(ruleInfo, ruleId, issueContext);
+ }
+ });
+ }
- ruleHelpToolWindow.UpdateContent(flowDocument);
+ private void ShowRuleInIde(IRuleInfo ruleInfo, SonarCompositeRuleId ruleId, string issueContext)
+ {
+ threadHandling.ThrowIfNotOnUIThread();
+ // Lazily fetch the tool window from a UI thread
+ ruleHelpToolWindow ??= toolWindowService.GetToolWindow();
- toolWindowService.Show(RuleHelpToolWindow.ToolWindowId);
- }
- catch (Exception ex) when (!ErrorHandler.IsCriticalException(ex))
- {
- logger.WriteLine(string.Format(Resources.ERR_RuleHelpToolWindow_Exception, ex));
- showRuleInBrowser.ShowRuleDescription(ruleId);
- }
+ try
+ {
+ var flowDocument = ruleHelpXamlBuilder.Create(ruleInfo, issueContext);
+
+ ruleHelpToolWindow.UpdateContent(flowDocument);
+
+ toolWindowService.Show(RuleHelpToolWindow.ToolWindowId);
+ }
+ catch (Exception ex) when (!ErrorHandler.IsCriticalException(ex))
+ {
+ logger.WriteLine(string.Format(Resources.ERR_RuleHelpToolWindow_Exception, ex));
+ showRuleInBrowser.ShowRuleDescription(ruleId);
}
}
}
diff --git a/src/Education/ErrorList/SonarErrorListEventProcessor.cs b/src/Education/ErrorList/SonarErrorListEventProcessor.cs
index 5c3828a5a..abfd9c6cb 100644
--- a/src/Education/ErrorList/SonarErrorListEventProcessor.cs
+++ b/src/Education/ErrorList/SonarErrorListEventProcessor.cs
@@ -23,50 +23,35 @@
using SonarLint.VisualStudio.Core;
using SonarLint.VisualStudio.Infrastructure.VS;
-namespace SonarLint.VisualStudio.Education
+namespace SonarLint.VisualStudio.Education.ErrorList;
+
+///
+/// Processor class that lets us handle WPF events from the Error List
+///
+internal class SonarErrorListEventProcessor(IEducation educationService, IErrorListHelper errorListHelper, ILogger logger) : TableControlEventProcessorBase
{
- namespace SonarLint.VisualStudio.Education.ErrorList
+ public override void PreprocessNavigateToHelp(
+ ITableEntryHandle entry,
+ TableEntryEventArgs e)
{
- ///
- /// Proccessor class that lets us handle WPF events from the Error List
- ///
- internal class SonarErrorListEventProcessor : TableControlEventProcessorBase
- {
- private readonly IEducation educationService;
- private readonly IErrorListHelper errorListHelper;
- private readonly ILogger logger;
-
- public SonarErrorListEventProcessor(IEducation educationService, IErrorListHelper errorListHelper, ILogger logger)
- {
- this.educationService = educationService;
- this.errorListHelper = errorListHelper;
- this.logger = logger;
- }
-
- public override void PreprocessNavigateToHelp(
- ITableEntryHandle entry,
- TableEntryEventArgs e)
- {
- // If the user is navigating to help for one of the Sonar rules,
- // show our rule description tool window
+ // If the user is navigating to help for one of the Sonar rules,
+ // show our rule description tool window
- Requires.NotNull(entry, nameof(entry));
+ Requires.NotNull(entry, nameof(entry));
- bool handled = false;
+ var handled = false;
- if (errorListHelper.TryGetRuleId(entry, out var ruleId))
- {
- errorListHelper.TryGetFilterableIssue(entry, out var filterableIssue);
- logger.LogVerbose(Resources.ErrorList_Processor_SonarRuleDetected, ruleId);
-
- educationService.ShowRuleHelp(ruleId, filterableIssue?.IssueId, /* todo by SLVS-1630 */null);
+ if (errorListHelper.TryGetRuleId(entry, out var ruleId))
+ {
+ errorListHelper.TryGetFilterableIssue(entry, out var filterableIssue);
+ logger.LogVerbose(Resources.ErrorList_Processor_SonarRuleDetected, ruleId);
- // Mark the event as handled to stop the normal VS "show help in browser" behaviour
- handled = true;
- }
+ educationService.ShowRuleHelp(ruleId, filterableIssue?.IssueId, /* todo by SLVS-1630 */null);
- e.Handled = handled;
- }
+ // Mark the event as handled to stop the normal VS "show help in browser" behaviour
+ handled = true;
}
+
+ e.Handled = handled;
}
}
diff --git a/src/Education/ErrorList/SonarErrorListEventProcessorProvider.cs b/src/Education/ErrorList/SonarErrorListEventProcessorProvider.cs
index c385a8fa2..f4deed3a9 100644
--- a/src/Education/ErrorList/SonarErrorListEventProcessorProvider.cs
+++ b/src/Education/ErrorList/SonarErrorListEventProcessorProvider.cs
@@ -24,43 +24,38 @@
using SonarLint.VisualStudio.Core;
using SonarLint.VisualStudio.Infrastructure.VS;
-namespace SonarLint.VisualStudio.Education
-{
- namespace SonarLint.VisualStudio.Education.ErrorList
- {
- // Notifies VS that we want to handle events from the Error List
+namespace SonarLint.VisualStudio.Education.ErrorList;
+// Notifies VS that we want to handle events from the Error List
- [Export(typeof(ITableControlEventProcessorProvider))]
- [Name("SonarLint ErrorList Event Processor")]
+[Export(typeof(ITableControlEventProcessorProvider))]
+[Name("SonarLint ErrorList Event Processor")]
- // Need to hook into the list of processors before the standard VS handler so we can
- // change the behaviour of the "navigate to help" action
- [Order(After = "Default Priority", Before = "ErrorListPackage Table Control Event Processor")]
- [ManagerType("ErrorsTable")]
+// Need to hook into the list of processors before the standard VS handler so we can
+// change the behaviour of the "navigate to help" action
+[Order(After = "Default Priority", Before = "ErrorListPackage Table Control Event Processor")]
+[ManagerType("ErrorsTable")]
- // TODO - DataSourceType/DataSource can both be used multiple times. Can we just register for our source and Roslyn?
- // Ideally, we'd only handle our own data source types. However, we also need to handle the Roslyn data source
- [DataSourceType("*")]
- [DataSource("*")]
- internal class SonarErrorListEventProcessorProvider : ITableControlEventProcessorProvider
- {
- private readonly IEducation educationService;
- private readonly IErrorListHelper errorListHelper;
- private readonly ILogger logger;
+// TODO - DataSourceType/DataSource can both be used multiple times. Can we just register for our source and Roslyn?
+// Ideally, we'd only handle our own data source types. However, we also need to handle the Roslyn data source
+[DataSourceType("*")]
+[DataSource("*")]
+internal class SonarErrorListEventProcessorProvider : ITableControlEventProcessorProvider
+{
+ private readonly IEducation educationService;
+ private readonly IErrorListHelper errorListHelper;
+ private readonly ILogger logger;
- [ImportingConstructor]
- public SonarErrorListEventProcessorProvider(IEducation educationService, IErrorListHelper errorListHelper, ILogger logger)
- {
- this.educationService = educationService;
- this.errorListHelper = errorListHelper;
- this.logger = logger;
- }
+ [ImportingConstructor]
+ public SonarErrorListEventProcessorProvider(IEducation educationService, IErrorListHelper errorListHelper, ILogger logger)
+ {
+ this.educationService = educationService;
+ this.errorListHelper = errorListHelper;
+ this.logger = logger;
+ }
- public ITableControlEventProcessor GetAssociatedEventProcessor(IWpfTableControl tableControl)
- {
- logger.LogVerbose(Resources.ErrorList_ProcessorCreated);
- return new SonarErrorListEventProcessor(educationService, errorListHelper, logger);
- }
- }
+ public ITableControlEventProcessor GetAssociatedEventProcessor(IWpfTableControl tableControl)
+ {
+ logger.LogVerbose(Resources.ErrorList_ProcessorCreated);
+ return new SonarErrorListEventProcessor(educationService, errorListHelper, logger);
}
}
diff --git a/src/Education/Rule/SLCoreRuleMetaDataProvider.cs b/src/Education/Rule/SLCoreRuleMetaDataProvider.cs
index 8986f656e..22f2231e6 100644
--- a/src/Education/Rule/SLCoreRuleMetaDataProvider.cs
+++ b/src/Education/Rule/SLCoreRuleMetaDataProvider.cs
@@ -29,25 +29,14 @@ namespace SonarLint.VisualStudio.Education.Rule;
[Export(typeof(IRuleMetaDataProvider))]
[PartCreationPolicy(CreationPolicy.Shared)]
-internal class SLCoreRuleMetaDataProvider : IRuleMetaDataProvider
+[method: ImportingConstructor]
+internal class SLCoreRuleMetaDataProvider(
+ ISLCoreServiceProvider slCoreServiceProvider,
+ IActiveConfigScopeTracker activeConfigScopeTracker,
+ IRuleInfoConverter ruleInfoConverter,
+ ILogger logger)
+ : IRuleMetaDataProvider
{
- private readonly IActiveConfigScopeTracker activeConfigScopeTracker;
- private readonly IRuleInfoConverter ruleInfoConverter;
- private readonly ILogger logger;
- private readonly ISLCoreServiceProvider slCoreServiceProvider;
-
- [ImportingConstructor]
- public SLCoreRuleMetaDataProvider(ISLCoreServiceProvider slCoreServiceProvider,
- IActiveConfigScopeTracker activeConfigScopeTracker,
- IRuleInfoConverter ruleInfoConverter,
- ILogger logger)
- {
- this.slCoreServiceProvider = slCoreServiceProvider;
- this.activeConfigScopeTracker = activeConfigScopeTracker;
- this.ruleInfoConverter = ruleInfoConverter;
- this.logger = logger;
- }
-
///
public async Task GetRuleInfoAsync(SonarCompositeRuleId ruleId, Guid? issueId = null)
{
diff --git a/src/Infrastructure.VS.UnitTests/ErrorListHelperTests.cs b/src/Infrastructure.VS.UnitTests/ErrorListHelperTests.cs
index ec70d46d4..4a9734cce 100644
--- a/src/Infrastructure.VS.UnitTests/ErrorListHelperTests.cs
+++ b/src/Infrastructure.VS.UnitTests/ErrorListHelperTests.cs
@@ -22,538 +22,480 @@
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.Shell.TableControl;
using Microsoft.VisualStudio.Shell.TableManager;
-using Moq;
using SonarLint.VisualStudio.IssueVisualization.Models;
-namespace SonarLint.VisualStudio.Infrastructure.VS.UnitTests
+namespace SonarLint.VisualStudio.Infrastructure.VS.UnitTests;
+
+[TestClass]
+public class ErrorListHelperTests
{
- [TestClass]
- public class ErrorListHelperTests
+ private IAnalysisIssueVisualization issueMock;
+ private ErrorListHelper testSubject;
+ private IVsUIServiceOperation vsUiServiceOperation;
+
+ [TestInitialize]
+ public void TestInitialize()
{
- internal enum TestVsSuppressionState
- {
- Active,
- Suppressed,
- NotApplicable,
- }
+ vsUiServiceOperation = Substitute.For();
+ issueMock = Substitute.For();
- [TestMethod]
- public void MefCtor_CheckIsExported()
- {
- MefTestHelpers.CheckTypeCanBeImported(
- MefTestHelpers.CreateExport());
- }
+ testSubject = new ErrorListHelper(vsUiServiceOperation);
+ }
- [TestMethod]
- public void MefCtor_CheckIsSingleton()
- => MefTestHelpers.CheckIsSingletonMefComponent();
+ [TestMethod]
+ public void MefCtor_CheckIsExported() =>
+ MefTestHelpers.CheckTypeCanBeImported(
+ MefTestHelpers.CreateExport());
- [TestMethod]
- public void MefCtor_DoesNotCallAnyServices()
- {
- var serviceOp = new Mock();
+ [TestMethod]
+ public void MefCtor_CheckIsSingleton() => MefTestHelpers.CheckIsSingletonMefComponent();
- _ = new ErrorListHelper(serviceOp.Object);
+ [TestMethod]
+ public void MefCtor_DoesNotCallAnyServices() =>
+ // The MEF constructor should be free-threaded, which it will be if
+ // it doesn't make any external calls.
+ vsUiServiceOperation.ReceivedCalls().Should().BeEmpty();
- // The MEF constructor should be free-threaded, which it will be if
- // it doesn't make any external calls.
- serviceOp.Invocations.Should().BeEmpty();
- }
-
- [TestMethod]
- public void TryGetIssueFromSelectedRow_SingleSonarIssue_IssueReturned()
- {
- var issueMock = Mock.Of();
- var issueHandle = CreateIssueHandle(111, new Dictionary
+ [TestMethod]
+ public void TryGetIssueFromSelectedRow_SingleSonarIssue_IssueReturned()
+ {
+ var issueHandle = CreateIssueHandle(111,
+ new Dictionary
{
{ StandardTableKeyNames.BuildTool, "SonarLint" },
- { StandardTableKeyNames.ErrorCode, "javascript:S333"},
+ { StandardTableKeyNames.ErrorCode, "javascript:S333" },
{ SonarLintTableControlConstants.IssueVizColumnName, issueMock }
});
- var errorList = CreateErrorList(issueHandle);
- var serviceProvider = CreateServiceOperation(errorList);
+ MockErrorList(issueHandle);
- var testSubject = new ErrorListHelper(serviceProvider);
- bool result = testSubject.TryGetIssueFromSelectedRow(out var issue);
+ var result = testSubject.TryGetIssueFromSelectedRow(out var issue);
- result.Should().BeTrue();
- issue.Should().BeSameAs(issueMock);
- }
+ result.Should().BeTrue();
+ issue.Should().BeSameAs(issueMock);
+ }
- [TestMethod]
- public void TryGetIssueFromSelectedRow_SingleItemButNoAnalysisIssue_IssueNotReturned()
- {
- var issueHandle = CreateIssueHandle(111, new Dictionary
+ [TestMethod]
+ public void TryGetIssueFromSelectedRow_SingleItemButNoAnalysisIssue_IssueNotReturned()
+ {
+ var issueHandle = CreateIssueHandle(111,
+ new Dictionary
{
{ StandardTableKeyNames.BuildTool, "SonarLint" },
- { StandardTableKeyNames.ErrorCode, "javascript:S333"},
+ { StandardTableKeyNames.ErrorCode, "javascript:S333" },
{ SonarLintTableControlConstants.IssueVizColumnName, null }
});
- var errorList = CreateErrorList(issueHandle);
- var serviceProvider = CreateServiceOperation(errorList);
+ MockErrorList(issueHandle);
- var testSubject = new ErrorListHelper(serviceProvider);
- var result = testSubject.TryGetIssueFromSelectedRow(out _);
+ var result = testSubject.TryGetIssueFromSelectedRow(out _);
- result.Should().BeFalse();
- }
+ result.Should().BeFalse();
+ }
- [TestMethod]
- public void TryGetIssueFromSelectedRow_MultipleItemsSelected_IssueNotReturned()
- {
- var cppIssueHandle = CreateIssueHandle(111, new Dictionary
+ [TestMethod]
+ public void TryGetIssueFromSelectedRow_MultipleItemsSelected_IssueNotReturned()
+ {
+ var cppIssueHandle = CreateIssueHandle(111,
+ new Dictionary
{
{ StandardTableKeyNames.BuildTool, "SonarLint" },
{ StandardTableKeyNames.ErrorCode, "cpp:S222" },
- { SonarLintTableControlConstants.IssueVizColumnName, Mock.Of() }
+ { SonarLintTableControlConstants.IssueVizColumnName, Substitute.For() }
});
- var jsIssueHandle = CreateIssueHandle(222, new Dictionary
+ var jsIssueHandle = CreateIssueHandle(222,
+ new Dictionary
{
{ StandardTableKeyNames.BuildTool, "SonarLint.CSharp" },
{ StandardTableKeyNames.ErrorCode, "csharpsquid:S222" },
- { SonarLintTableControlConstants.IssueVizColumnName, Mock.Of() }
+ { SonarLintTableControlConstants.IssueVizColumnName, Substitute.For() }
});
+ MockErrorList(cppIssueHandle, jsIssueHandle);
- var errorList = CreateErrorList(cppIssueHandle, jsIssueHandle);
- var serviceProvider = CreateServiceOperation(errorList);
+ var result = testSubject.TryGetIssueFromSelectedRow(out _);
- var testSubject = new ErrorListHelper(serviceProvider);
- var result = testSubject.TryGetIssueFromSelectedRow(out _);
-
- result.Should().BeFalse();
- }
+ result.Should().BeFalse();
+ }
- [TestMethod]
- public void TryGetRoslynIssueFromSelectedRow_SingleRoslynIssue_IssueReturned()
- {
- var path = "filepath";
- var line = 12;
- var column = 101;
- var errorCode = "javascript:S333";
- var issueHandle = CreateIssueHandle(111, new Dictionary
+ [TestMethod]
+ public void TryGetRoslynIssueFromSelectedRow_SingleRoslynIssue_IssueReturned()
+ {
+ var path = "filepath";
+ var line = 12;
+ var column = 101;
+ var errorCode = "javascript:S333";
+ var issueHandle = CreateIssueHandle(111,
+ new Dictionary
{
{ StandardTableKeyNames.BuildTool, "SonarLint" },
- { StandardTableKeyNames.ErrorCode, errorCode},
+ { StandardTableKeyNames.ErrorCode, errorCode },
{ StandardTableKeyNames.DocumentName, path },
{ StandardTableKeyNames.Line, line },
{ StandardTableKeyNames.Column, column }
});
- var errorList = CreateErrorList(issueHandle);
- var serviceProvider = CreateServiceOperation(errorList);
-
- var testSubject = new ErrorListHelper(serviceProvider);
- bool result = testSubject.TryGetRoslynIssueFromSelectedRow(out var issue);
-
- result.Should().BeTrue();
- issue.RuleId.Should().BeSameAs(errorCode);
- issue.FilePath.Should().BeSameAs(path);
- issue.StartLine.Should().Be(line + 1);
- issue.RoslynStartLine.Should().Be(line + 1);
- issue.RoslynStartColumn.Should().Be(column + 1);
- issue.LineHash.Should().BeNull();
- }
+ MockErrorList(issueHandle);
- [TestMethod]
- public void TryGetRoslynIssueFromSelectedRow_NonSonarIssue_NothingReturned()
- {
- var issueHandle = CreateIssueHandle(111, new Dictionary
+ var result = testSubject.TryGetRoslynIssueFromSelectedRow(out var issue);
+
+ result.Should().BeTrue();
+ issue.RuleId.Should().BeSameAs(errorCode);
+ issue.FilePath.Should().BeSameAs(path);
+ issue.StartLine.Should().Be(line + 1);
+ issue.RoslynStartLine.Should().Be(line + 1);
+ issue.RoslynStartColumn.Should().Be(column + 1);
+ issue.LineHash.Should().BeNull();
+ }
+
+ [TestMethod]
+ public void TryGetRoslynIssueFromSelectedRow_NonSonarIssue_NothingReturned()
+ {
+ var issueHandle = CreateIssueHandle(111,
+ new Dictionary
{
{ StandardTableKeyNames.BuildTool, "Not SonarLint" },
- { StandardTableKeyNames.ErrorCode, "javascript:S333"},
+ { StandardTableKeyNames.ErrorCode, "javascript:S333" },
{ StandardTableKeyNames.DocumentName, "filepath" },
{ StandardTableKeyNames.Line, 1 },
{ StandardTableKeyNames.Column, 2 }
});
- var errorList = CreateErrorList(issueHandle);
- var serviceProvider = CreateServiceOperation(errorList);
+ MockErrorList(issueHandle);
- var testSubject = new ErrorListHelper(serviceProvider);
- bool result = testSubject.TryGetRoslynIssueFromSelectedRow(out _);
+ var result = testSubject.TryGetRoslynIssueFromSelectedRow(out _);
- result.Should().BeFalse();
- }
+ result.Should().BeFalse();
+ }
- [TestMethod]
- public void TryGetRoslynIssueFromSelectedRow_NoFilePath_NothingReturned()
- {
- var issueHandle = CreateIssueHandle(111, new Dictionary
+ [TestMethod]
+ public void TryGetRoslynIssueFromSelectedRow_NoFilePath_NothingReturned()
+ {
+ var issueHandle = CreateIssueHandle(111,
+ new Dictionary
{
{ StandardTableKeyNames.BuildTool, "SonarLint" },
- { StandardTableKeyNames.ErrorCode, "javascript:S333"},
- { StandardTableKeyNames.Line, 1 },
- { StandardTableKeyNames.Column, 2 }
+ { StandardTableKeyNames.ErrorCode, "javascript:S333" },
+ { StandardTableKeyNames.Line, 1 }, { StandardTableKeyNames.Column, 2 }
});
- var errorList = CreateErrorList(issueHandle);
- var serviceProvider = CreateServiceOperation(errorList);
+ MockErrorList(issueHandle);
- var testSubject = new ErrorListHelper(serviceProvider);
- bool result = testSubject.TryGetRoslynIssueFromSelectedRow(out _);
+ var result = testSubject.TryGetRoslynIssueFromSelectedRow(out _);
- result.Should().BeFalse();
- }
+ result.Should().BeFalse();
+ }
- [TestMethod]
- public void TryGetRoslynIssueFromSelectedRow_NoStartLine_NothingReturned()
- {
- var issueHandle = CreateIssueHandle(111, new Dictionary
+ [TestMethod]
+ public void TryGetRoslynIssueFromSelectedRow_NoStartLine_NothingReturned()
+ {
+ var issueHandle = CreateIssueHandle(111,
+ new Dictionary
{
{ StandardTableKeyNames.BuildTool, "SonarLint" },
- { StandardTableKeyNames.ErrorCode, "javascript:S333"},
+ { StandardTableKeyNames.ErrorCode, "javascript:S333" },
{ StandardTableKeyNames.DocumentName, "filepath" },
- { StandardTableKeyNames.Column, 2 },
+ { StandardTableKeyNames.Column, 2 }
});
- var errorList = CreateErrorList(issueHandle);
- var serviceProvider = CreateServiceOperation(errorList);
+ MockErrorList(issueHandle);
- var testSubject = new ErrorListHelper(serviceProvider);
- bool result = testSubject.TryGetRoslynIssueFromSelectedRow(out _);
+ var result = testSubject.TryGetRoslynIssueFromSelectedRow(out _);
- result.Should().BeFalse();
- }
+ result.Should().BeFalse();
+ }
- [TestMethod]
- public void TryGetRoslynIssueFromSelectedRow_NoStartColumn_NothingReturned()
- {
- var issueHandle = CreateIssueHandle(111, new Dictionary
+ [TestMethod]
+ public void TryGetRoslynIssueFromSelectedRow_NoStartColumn_NothingReturned()
+ {
+ var issueHandle = CreateIssueHandle(111,
+ new Dictionary
{
{ StandardTableKeyNames.BuildTool, "SonarLint" },
- { StandardTableKeyNames.ErrorCode, "javascript:S333"},
+ { StandardTableKeyNames.ErrorCode, "javascript:S333" },
{ StandardTableKeyNames.DocumentName, "filepath" },
- { StandardTableKeyNames.Line, 1 },
+ { StandardTableKeyNames.Line, 1 }
});
- var errorList = CreateErrorList(issueHandle);
- var serviceProvider = CreateServiceOperation(errorList);
+ MockErrorList(issueHandle);
- var testSubject = new ErrorListHelper(serviceProvider);
- bool result = testSubject.TryGetRoslynIssueFromSelectedRow(out _);
+ var result = testSubject.TryGetRoslynIssueFromSelectedRow(out _);
- result.Should().BeFalse();
- }
-
- [TestMethod]
- [DataRow("S666", "csharpsquid", "S666", "SonarAnalyzer.CSharp", null)]
- [DataRow("S666", "vbnet", "S666", "SonarAnalyzer.VisualBasic", null)]
- [DataRow("S234", "vbnet", "S234", "SonarAnalyzer.VisualBasic", null)]
- [DataRow("c:S111", "c", "S111", "SonarLint", null)]
- [DataRow("cpp:S222", "cpp", "S222", "SonarLint", null)]
- [DataRow("javascript:S333", "javascript", "S333", "SonarLint", null)]
- [DataRow("typescript:S444", "typescript", "S444", "SonarLint", null)]
- [DataRow("secrets:S555", "secrets", "S555", "SonarLint", null)]
- [DataRow("foo:bar", "foo", "bar", "SonarLint", null)]
- [DataRow("S666", "csharpsquid", "S666", null, "https://rules.sonarsource.com/csharp/RSPEC-666/")]
- [DataRow("S666", "vbnet", "S666", null, "https://rules.sonarsource.com/vbnet/RSPEC-666/")]
- [DataRow("S234", "vbnet", "S234", null, "https://rules.sonarsource.com/vbnet/RSPEC-234/")]
- public void TryGetRuleIdFromSelectedRow_SingleSonarIssue_ErrorCodeReturned(string fullRuleKey, string expectedRepo, string expectedRule, string buildTool, string helpLink)
- {
- // Arrange
- var issueHandle = CreateIssueHandle(111, new Dictionary
- {
- { StandardTableKeyNames.BuildTool, buildTool },
- { StandardTableKeyNames.HelpLink, helpLink },
- { StandardTableKeyNames.ErrorCode, fullRuleKey }
- });
-
- var errorList = CreateErrorList(issueHandle);
- var serviceProvider = CreateServiceOperation(errorList);
+ result.Should().BeFalse();
+ }
- // Act
- var testSubject = new ErrorListHelper(serviceProvider);
- bool result = testSubject.TryGetRuleIdFromSelectedRow(out var ruleId);
+ [TestMethod]
+ [DataRow("S666", "csharpsquid", "S666", "SonarAnalyzer.CSharp", null)]
+ [DataRow("S666", "vbnet", "S666", "SonarAnalyzer.VisualBasic", null)]
+ [DataRow("S234", "vbnet", "S234", "SonarAnalyzer.VisualBasic", null)]
+ [DataRow("c:S111", "c", "S111", "SonarLint", null)]
+ [DataRow("cpp:S222", "cpp", "S222", "SonarLint", null)]
+ [DataRow("javascript:S333", "javascript", "S333", "SonarLint", null)]
+ [DataRow("typescript:S444", "typescript", "S444", "SonarLint", null)]
+ [DataRow("secrets:S555", "secrets", "S555", "SonarLint", null)]
+ [DataRow("foo:bar", "foo", "bar", "SonarLint", null)]
+ [DataRow("S666", "csharpsquid", "S666", null, "https://rules.sonarsource.com/csharp/RSPEC-666/")]
+ [DataRow("S666", "vbnet", "S666", null, "https://rules.sonarsource.com/vbnet/RSPEC-666/")]
+ [DataRow("S234", "vbnet", "S234", null, "https://rules.sonarsource.com/vbnet/RSPEC-234/")]
+ public void TryGetRuleIdFromSelectedRow_SingleSonarIssue_ErrorCodeReturned(
+ string fullRuleKey,
+ string expectedRepo,
+ string expectedRule,
+ string buildTool,
+ string helpLink)
+ {
+ var issueHandle = CreateIssueHandle(111,
+ new Dictionary { { StandardTableKeyNames.BuildTool, buildTool }, { StandardTableKeyNames.HelpLink, helpLink }, { StandardTableKeyNames.ErrorCode, fullRuleKey } });
+ MockErrorList(issueHandle);
- // Assert
- result.Should().BeTrue();
- ruleId.RepoKey.Should().Be(expectedRepo);
- ruleId.RuleKey.Should().Be(expectedRule);
- }
+ var result = testSubject.TryGetRuleIdFromSelectedRow(out var ruleId);
- [TestMethod]
- [DataRow("S666", "csharpsquid", "S666", "SonarAnalyzer.CSharp", null)]
- [DataRow("S666", "vbnet", "S666", "SonarAnalyzer.VisualBasic", null)]
- [DataRow("S234", "vbnet", "S234", "SonarAnalyzer.VisualBasic", null)]
- [DataRow("c:S111", "c", "S111", "SonarLint", null)]
- [DataRow("cpp:S222", "cpp", "S222", "SonarLint", null)]
- [DataRow("javascript:S333", "javascript", "S333", "SonarLint", null)]
- [DataRow("typescript:S444", "typescript", "S444", "SonarLint", null)]
- [DataRow("secrets:S555", "secrets", "S555", "SonarLint", null)]
- [DataRow("foo:bar", "foo", "bar", "SonarLint", null)]
- [DataRow("S666", "csharpsquid", "S666", null, "https://rules.sonarsource.com/csharp/RSPEC-666/")]
- [DataRow("S666", "vbnet", "S666", null, "https://rules.sonarsource.com/vbnet/RSPEC-666/")]
- [DataRow("S234", "vbnet", "S234", null, "https://rules.sonarsource.com/vbnet/RSPEC-234/")]
- public void TryGetRuleId_FromHandle_ErrorCodeReturned(string fullRuleKey, string expectedRepo, string expectedRule, string buildTool, string helpLink)
- {
- // Note: this is a copy of TryGetRuleIdFromSelectedRow_SingleSonarIssue_ErrorCodeReturned,
- // but without the serviceProvider and IErrorList setup
+ result.Should().BeTrue();
+ ruleId.RepoKey.Should().Be(expectedRepo);
+ ruleId.RuleKey.Should().Be(expectedRule);
+ }
- // Arrange
- var issueHandle = CreateIssueHandle(111, new Dictionary
- {
- { StandardTableKeyNames.BuildTool, buildTool },
- { StandardTableKeyNames.HelpLink, helpLink },
- { StandardTableKeyNames.ErrorCode, fullRuleKey }
- });
+ [TestMethod]
+ [DataRow("S666", "csharpsquid", "S666", "SonarAnalyzer.CSharp", null)]
+ [DataRow("S666", "vbnet", "S666", "SonarAnalyzer.VisualBasic", null)]
+ [DataRow("S234", "vbnet", "S234", "SonarAnalyzer.VisualBasic", null)]
+ [DataRow("c:S111", "c", "S111", "SonarLint", null)]
+ [DataRow("cpp:S222", "cpp", "S222", "SonarLint", null)]
+ [DataRow("javascript:S333", "javascript", "S333", "SonarLint", null)]
+ [DataRow("typescript:S444", "typescript", "S444", "SonarLint", null)]
+ [DataRow("secrets:S555", "secrets", "S555", "SonarLint", null)]
+ [DataRow("foo:bar", "foo", "bar", "SonarLint", null)]
+ [DataRow("S666", "csharpsquid", "S666", null, "https://rules.sonarsource.com/csharp/RSPEC-666/")]
+ [DataRow("S666", "vbnet", "S666", null, "https://rules.sonarsource.com/vbnet/RSPEC-666/")]
+ [DataRow("S234", "vbnet", "S234", null, "https://rules.sonarsource.com/vbnet/RSPEC-234/")]
+ public void TryGetRuleId_FromHandle_ErrorCodeReturned(
+ string fullRuleKey,
+ string expectedRepo,
+ string expectedRule,
+ string buildTool,
+ string helpLink)
+ {
+ // Note: this is a copy of TryGetRuleIdFromSelectedRow_SingleSonarIssue_ErrorCodeReturned,
+ // but without the serviceProvider and IErrorList setup
+ var issueHandle = CreateIssueHandle(111,
+ new Dictionary { { StandardTableKeyNames.BuildTool, buildTool }, { StandardTableKeyNames.HelpLink, helpLink }, { StandardTableKeyNames.ErrorCode, fullRuleKey } });
- // Act
- var testSubject = new ErrorListHelper(Mock.Of());
- bool result = testSubject.TryGetRuleId(issueHandle, out var ruleId);
+ var result = testSubject.TryGetRuleId(issueHandle, out var ruleId);
- // Assert
- result.Should().BeTrue();
- ruleId.RepoKey.Should().Be(expectedRepo);
- ruleId.RuleKey.Should().Be(expectedRule);
- }
+ result.Should().BeTrue();
+ ruleId.RepoKey.Should().Be(expectedRepo);
+ ruleId.RuleKey.Should().Be(expectedRule);
+ }
- [TestMethod]
- public void TryGetRuleIdFromSelectedRow_NonStandardErrorCode_NoException_ErrorCodeNotReturned()
+ [TestMethod]
+ public void TryGetRuleIdFromSelectedRow_NonStandardErrorCode_NoException_ErrorCodeNotReturned()
+ {
+ var issueHandle = CreateIssueHandle(111, new Dictionary
{
- // Arrange
- var issueHandle = CreateIssueHandle(111, new Dictionary
- {
- { StandardTableKeyNames.BuildTool, "SonarLint" },
- { StandardTableKeyNames.ErrorCode, ":" } // should not happen
- });
+ { StandardTableKeyNames.BuildTool, "SonarLint" },
+ { StandardTableKeyNames.ErrorCode, ":" } // should not happen
+ });
+ MockErrorList(issueHandle);
- var errorList = CreateErrorList(issueHandle);
- var serviceProvider = CreateServiceOperation(errorList);
+ var result = testSubject.TryGetRuleIdFromSelectedRow(out var errorCode);
- // Act
- var testSubject = new ErrorListHelper(serviceProvider);
- bool result = testSubject.TryGetRuleIdFromSelectedRow(out var errorCode);
-
- // Assert
- result.Should().BeFalse();
- errorCode.Should().BeNull();
- }
+ result.Should().BeFalse();
+ errorCode.Should().BeNull();
+ }
- [TestMethod]
- public void TryGetRuleIdFromSelectedRow_MultipleItemsSelected_ErrorCodeNotReturned()
+ [TestMethod]
+ public void TryGetRuleIdFromSelectedRow_MultipleItemsSelected_ErrorCodeNotReturned()
+ {
+ var cppIssueHandle = CreateIssueHandle(111, new Dictionary
{
- var cppIssueHandle = CreateIssueHandle(111, new Dictionary
- {
- { StandardTableKeyNames.BuildTool, "SonarLint" },
- { StandardTableKeyNames.ErrorCode, "cpp:S222" }
- });
- var jsIssueHandle = CreateIssueHandle(222, new Dictionary
- {
- { StandardTableKeyNames.BuildTool, "SonarLint.CSharp" },
- { StandardTableKeyNames.ErrorCode, "csharpsquid:S222" }
- });
-
- var errorList = CreateErrorList(cppIssueHandle, jsIssueHandle);
- var serviceProvider = CreateServiceOperation(errorList);
+ { StandardTableKeyNames.BuildTool, "SonarLint" },
+ { StandardTableKeyNames.ErrorCode, "cpp:S222" }
+ });
+ var jsIssueHandle = CreateIssueHandle(222, new Dictionary
+ {
+ { StandardTableKeyNames.BuildTool, "SonarLint.CSharp" },
+ { StandardTableKeyNames.ErrorCode, "csharpsquid:S222" }
+ });
+ MockErrorList(cppIssueHandle, jsIssueHandle);
- // Act
- var testSubject = new ErrorListHelper(serviceProvider);
- bool result = testSubject.TryGetRuleIdFromSelectedRow(out var errorCode);
+ var result = testSubject.TryGetRuleIdFromSelectedRow(out var errorCode);
- // Assert
- result.Should().BeFalse();
- errorCode.Should().BeNull();
- }
+ result.Should().BeFalse();
+ errorCode.Should().BeNull();
+ }
- [TestMethod]
- public void TryGetRuleIdFromSelectedRow_NotSonarLintIssue()
+ [TestMethod]
+ public void TryGetRuleIdFromSelectedRow_NotSonarLintIssue()
+ {
+ var issueHandle = CreateIssueHandle(111, new Dictionary
{
- // Arrange
- var issueHandle = CreateIssueHandle(111, new Dictionary
- {
- { StandardTableKeyNames.BuildTool, new object() },
- { StandardTableKeyNames.ErrorCode, "cpp:S333" }
- });
+ { StandardTableKeyNames.BuildTool, new object() },
+ { StandardTableKeyNames.ErrorCode, "cpp:S333" }
+ });
+ MockErrorList(issueHandle);
- var errorList = CreateErrorList(issueHandle);
- var serviceProvider = CreateServiceOperation(errorList);
+ var result = testSubject.TryGetRuleIdFromSelectedRow(out var errorCode);
- // Act
- var testSubject = new ErrorListHelper(serviceProvider);
- bool result = testSubject.TryGetRuleIdFromSelectedRow(out var errorCode);
-
- // Assert
- result.Should().BeFalse();
- errorCode.Should().BeNull();
- }
+ result.Should().BeFalse();
+ errorCode.Should().BeNull();
+ }
- [TestMethod]
- [DataRow("cpp:S333", "AnotherAnalyzer", null)]
- [DataRow("S666", "AnotherAnalyzerWithSonarHelpLink", "https://rules.sonarsource.com/csharp/RSPEC-666/")]
- [DataRow("S234", "SomeOtherAnalyzer", "https://rules.sonarsource.com/vbnet/RSPEC-234/")]
- public void TryGetRuleId_FromHandle_NotSonarLintIssue(string fullRuleKey, object buildTool, string helpLink)
+ [TestMethod]
+ [DataRow("cpp:S333", "AnotherAnalyzer", null)]
+ [DataRow("S666", "AnotherAnalyzerWithSonarHelpLink", "https://rules.sonarsource.com/csharp/RSPEC-666/")]
+ [DataRow("S234", "SomeOtherAnalyzer", "https://rules.sonarsource.com/vbnet/RSPEC-234/")]
+ public void TryGetRuleId_FromHandle_NotSonarLintIssue(string fullRuleKey, object buildTool, string helpLink)
+ {
+ // Note: this is a copy of TryGetRuleIdFromSelectedRow_SingleSonarIssue_ErrorCodeReturned,
+ // but without the serviceProvider and IErrorList setup
+ var issueHandle = CreateIssueHandle(111, new Dictionary
{
- // Note: this is a copy of TryGetRuleIdFromSelectedRow_SingleSonarIssue_ErrorCodeReturned,
- // but without the serviceProvider and IErrorList setup
+ { StandardTableKeyNames.BuildTool, buildTool },
+ { StandardTableKeyNames.HelpLink, helpLink },
+ { StandardTableKeyNames.ErrorCode, fullRuleKey }
+ });
- // Arrange
- var issueHandle = CreateIssueHandle(111, new Dictionary
- {
- { StandardTableKeyNames.BuildTool, buildTool },
- { StandardTableKeyNames.HelpLink, helpLink },
- { StandardTableKeyNames.ErrorCode, fullRuleKey }
- });
-
- // Act
- var testSubject = new ErrorListHelper(Mock.Of());
- bool result = testSubject.TryGetRuleId(issueHandle, out var errorCode);
+ var result = testSubject.TryGetRuleId(issueHandle, out var errorCode);
- // Assert
- result.Should().BeFalse();
- errorCode.Should().BeNull();
- }
+ result.Should().BeFalse();
+ errorCode.Should().BeNull();
+ }
- [TestMethod]
- public void TryGetRuleIdAndSuppressionStateFromSelectedRow_NoSuppressionState_ReturnsIsNotSuppressed()
+ [TestMethod]
+ public void TryGetRuleIdAndSuppressionStateFromSelectedRow_NoSuppressionState_ReturnsIsNotSuppressed()
+ {
+ var issueHandle = CreateIssueHandle(111, new Dictionary
{
- // Arrange
- var issueHandle = CreateIssueHandle(111, new Dictionary
- {
- { StandardTableKeyNames.BuildTool, "SonarLint" },
- { StandardTableKeyNames.ErrorCode, "cpp:S222" }
- });
+ { StandardTableKeyNames.BuildTool, "SonarLint" },
+ { StandardTableKeyNames.ErrorCode, "cpp:S222" }
+ });
+ MockErrorList(issueHandle);
- var errorList = CreateErrorList(issueHandle);
- var serviceProvider = CreateServiceOperation(errorList);
+ var result = testSubject.TryGetRuleIdAndSuppressionStateFromSelectedRow(out _, out var isSuppressed);
- // Act
- var testSubject = new ErrorListHelper(serviceProvider);
- bool result = testSubject.TryGetRuleIdAndSuppressionStateFromSelectedRow(out var ruleId, out var isSuppressed);
-
- // Assert
- result.Should().BeTrue();
- isSuppressed.Should().BeFalse();
- }
+ result.Should().BeTrue();
+ isSuppressed.Should().BeFalse();
+ }
- [DataTestMethod]
- [DataRow(SuppressionState.Suppressed, true)]
- [DataRow(SuppressionState.NotApplicable, false)]
- [DataRow(SuppressionState.Active, false)]
- public void TryGetRuleIdAndSuppressionStateFromSelectedRow_NoSuppressionState_ReturnsIsNotSuppressed(SuppressionState suppressionState, bool expectedSuppression)
- {
- // Arrange
- var issueHandle = CreateIssueHandle(111, new Dictionary
+ [DataTestMethod]
+ [DataRow(SuppressionState.Suppressed, true)]
+ [DataRow(SuppressionState.NotApplicable, false)]
+ [DataRow(SuppressionState.Active, false)]
+ public void TryGetRuleIdAndSuppressionStateFromSelectedRow_NoSuppressionState_ReturnsIsNotSuppressed(SuppressionState suppressionState, bool expectedSuppression)
+ {
+ var issueHandle = CreateIssueHandle(111,
+ new Dictionary
{
{ StandardTableKeyNames.BuildTool, "SonarLint" },
{ StandardTableKeyNames.ErrorCode, "cpp:S222" },
- { StandardTableKeyNames.SuppressionState, suppressionState },
+ { StandardTableKeyNames.SuppressionState, suppressionState }
});
+ MockErrorList(issueHandle);
- var errorList = CreateErrorList(issueHandle);
- var serviceProvider = CreateServiceOperation(errorList);
-
- // Act
- var testSubject = new ErrorListHelper(serviceProvider);
- bool result = testSubject.TryGetRuleIdAndSuppressionStateFromSelectedRow(out var ruleId, out var isSuppressed);
+ var result = testSubject.TryGetRuleIdAndSuppressionStateFromSelectedRow(out _, out var isSuppressed);
- // Assert
- result.Should().BeTrue();
- isSuppressed.Should().Be(expectedSuppression);
- }
+ result.Should().BeTrue();
+ isSuppressed.Should().Be(expectedSuppression);
+ }
- [TestMethod]
- public void TryGetFilterableIssue_SonarIssue_IssueReturned()
- {
- var issueMock = Mock.Of();
- var issueHandle = CreateIssueHandle(111, new Dictionary
+ [TestMethod]
+ public void TryGetFilterableIssue_SonarIssue_IssueReturned()
+ {
+ var issueHandle = CreateIssueHandle(111,
+ new Dictionary
{
{ StandardTableKeyNames.BuildTool, "SonarLint" },
- { StandardTableKeyNames.ErrorCode, "javascript:S333"},
+ { StandardTableKeyNames.ErrorCode, "javascript:S333" },
{ SonarLintTableControlConstants.IssueVizColumnName, issueMock }
});
- var errorList = CreateErrorList(issueHandle);
- var serviceProvider = CreateServiceOperation(errorList);
- var testSubject = new ErrorListHelper(serviceProvider);
+ MockErrorList(issueHandle);
- bool result = testSubject.TryGetFilterableIssue(issueHandle, out var issue);
+ var result = testSubject.TryGetFilterableIssue(issueHandle, out var issue);
- result.Should().BeTrue();
- issue.Should().BeSameAs(issueMock);
- }
+ result.Should().BeTrue();
+ issue.Should().BeSameAs(issueMock);
+ }
- [TestMethod]
- public void TryGetFilterableIssue_NoAnalysisIssue_IssueNotReturned()
- {
- var issueHandle = CreateIssueHandle(111, new Dictionary
+ [TestMethod]
+ public void TryGetFilterableIssue_NoAnalysisIssue_IssueNotReturned()
+ {
+ var issueHandle = CreateIssueHandle(111,
+ new Dictionary
{
{ StandardTableKeyNames.BuildTool, "SonarLint" },
- { StandardTableKeyNames.ErrorCode, "javascript:S333"},
+ { StandardTableKeyNames.ErrorCode, "javascript:S333" },
{ SonarLintTableControlConstants.IssueVizColumnName, null }
});
- var errorList = CreateErrorList(issueHandle);
- var serviceProvider = CreateServiceOperation(errorList);
-
- var testSubject = new ErrorListHelper(serviceProvider);
- var result = testSubject.TryGetFilterableIssue(issueHandle,out _);
+ MockErrorList(issueHandle);
- result.Should().BeFalse();
- }
+ var result = testSubject.TryGetFilterableIssue(issueHandle, out _);
- private IVsUIServiceOperation CreateServiceOperation(IErrorList svcToPassToCallback)
- {
- var serviceOp = new Mock();
+ result.Should().BeFalse();
+ }
- // Set up the mock to invoke the operation with the supplied VS service
- serviceOp.Setup(x => x.Execute(It.IsAny>()))
- .Returns>(op => op(svcToPassToCallback));
+ private void MockErrorList(params ITableEntryHandle[] entries)
+ {
+ var errorList = CreateErrorList(entries);
+ // Set up the mock to invoke the operation with the supplied VS service
+ vsUiServiceOperation.Execute(Arg.Any>())
+ .Returns(callInfo =>
+ {
+ var func = callInfo.Arg>();
+ return func(errorList);
+ });
+ }
- return serviceOp.Object;
- }
+ private static IErrorList CreateErrorList(params ITableEntryHandle[] entries)
+ {
+ var mockWpfTable = Substitute.For();
+ mockWpfTable.SelectedEntries.Returns(entries);
- private static IErrorList CreateErrorList(params ITableEntryHandle[] entries)
- {
- var mockWpfTable = new Mock();
- mockWpfTable.Setup(x => x.SelectedEntries).Returns(entries);
+ var mockErrorList = Substitute.For();
+ mockErrorList.TableControl.Returns(mockWpfTable);
+ return mockErrorList;
+ }
- var mockErrorList = new Mock();
- mockErrorList.Setup(x => x.TableControl).Returns(mockWpfTable.Object);
- return mockErrorList.Object;
- }
+ private static ITableEntryHandle CreateIssueHandle(int index, IDictionary issueProperties)
+ {
+ // Snapshots would normally have multiple versions; each version would have a unique
+ // index, with a corresponding handle.
+ // Here, just create a dummy snapshot with a single version using the specified index
+ var issueSnapshot = (ITableEntriesSnapshot)new DummySnapshot { Index = index, Properties = issueProperties };
- private static ITableEntryHandle CreateIssueHandle(int index, IDictionary issueProperties)
+ var mockHandle = Substitute.For();
+ mockHandle.TryGetSnapshot(out _, out _).Returns(callInfo =>
{
- // Snapshots would normally have multiple versions; each version would have a unique
- // index, with a corresponding handle.
- // Here, just create a dummy snapshot with a single version using the specified index
- var issueSnapshot = (ITableEntriesSnapshot)new DummySnapshot
- {
- Index = index,
- Properties = issueProperties
- };
-
- var mockHandle = new Mock();
- mockHandle.Setup(x => x.TryGetSnapshot(out issueSnapshot, out index)).Returns(true);
- return mockHandle.Object;
- }
+ callInfo[0] = issueSnapshot;
+ callInfo[1] = index;
+ return true;
+ });
+ return mockHandle;
+ }
- #region Helper classes
+ #region Helper classes
- private sealed class DummySnapshot : ITableEntriesSnapshot
- {
- public int Index { get; set; }
- public IDictionary Properties { get; set; }
+ private sealed class DummySnapshot : ITableEntriesSnapshot
+ {
+ public int Index { get; set; }
+ public IDictionary Properties { get; set; }
- #region ITableEntriesSnapshot methods
+ #region ITableEntriesSnapshot methods
- public int Count => throw new NotImplementedException();
- public int VersionNumber => throw new NotImplementedException();
+ public int Count => throw new NotImplementedException();
+ public int VersionNumber => throw new NotImplementedException();
- public void Dispose() => throw new NotImplementedException();
+ public void Dispose() => throw new NotImplementedException();
- public int IndexOf(int currentIndex, ITableEntriesSnapshot newSnapshot) => throw new NotImplementedException();
+ public int IndexOf(int currentIndex, ITableEntriesSnapshot newSnapshot) => throw new NotImplementedException();
- public void StartCaching() => throw new NotImplementedException();
+ public void StartCaching() => throw new NotImplementedException();
- public void StopCaching() => throw new NotImplementedException();
+ public void StopCaching() => throw new NotImplementedException();
- public bool TryGetValue(int index, string keyName, out object content)
+ public bool TryGetValue(int index, string keyName, out object content)
+ {
+ if (index == Index)
{
- if (index == Index)
- {
- return Properties.TryGetValue(keyName, out content);
- }
- content = null;
- return false;
+ return Properties.TryGetValue(keyName, out content);
}
-
- #endregion ITableEntriesSnapshot methods
+ content = null;
+ return false;
}
- #endregion Helper classes
+ #endregion ITableEntriesSnapshot methods
}
+
+ #endregion Helper classes
}
diff --git a/src/Infrastructure.VS/ErrorListHelper.cs b/src/Infrastructure.VS/ErrorListHelper.cs
index 4beb5f0b8..f31c474f9 100644
--- a/src/Infrastructure.VS/ErrorListHelper.cs
+++ b/src/Infrastructure.VS/ErrorListHelper.cs
@@ -26,209 +26,199 @@
using SonarLint.VisualStudio.Core;
using SonarLint.VisualStudio.Core.Suppressions;
-namespace SonarLint.VisualStudio.Infrastructure.VS
+namespace SonarLint.VisualStudio.Infrastructure.VS;
+
+[Export(typeof(IErrorListHelper))]
+[PartCreationPolicy(CreationPolicy.Shared)]
+[method: ImportingConstructor]
+public class ErrorListHelper(IVsUIServiceOperation vSServiceOperation) : IErrorListHelper
{
- [Export(typeof(IErrorListHelper))]
- [PartCreationPolicy(CreationPolicy.Shared)]
- public class ErrorListHelper : IErrorListHelper
+ public bool TryGetRuleIdFromSelectedRow(out SonarCompositeRuleId ruleId)
{
- private readonly IVsUIServiceOperation vSServiceOperation;
+ SonarCompositeRuleId ruleIdOut = null;
+ var result = vSServiceOperation.Execute(errorList =>
+ TryGetSelectedTableEntry(errorList, out var handle) && TryGetRuleId(handle, out ruleIdOut));
- [ImportingConstructor]
- public ErrorListHelper(IVsUIServiceOperation vSServiceOperation)
- {
- this.vSServiceOperation = vSServiceOperation;
- }
-
- public bool TryGetRuleIdFromSelectedRow(out SonarCompositeRuleId ruleId)
- {
- SonarCompositeRuleId ruleIdOut = null;
- var result = vSServiceOperation.Execute(errorList =>
- TryGetSelectedTableEntry(errorList, out var handle) && TryGetRuleId(handle, out ruleIdOut));
+ ruleId = ruleIdOut;
- ruleId = ruleIdOut;
+ return result;
+ }
- return result;
+ public bool TryGetRuleId(ITableEntryHandle handle, out SonarCompositeRuleId ruleId)
+ {
+ ruleId = null;
+ if (!handle.TryGetSnapshot(out var snapshot, out var index))
+ {
+ return false;
}
- public bool TryGetRuleId(ITableEntryHandle handle, out SonarCompositeRuleId ruleId)
+ var errorCode = FindErrorCodeForEntry(snapshot, index);
+ return SonarCompositeRuleId.TryParse(errorCode, out ruleId);
+ }
+
+ public bool TryGetRuleIdAndSuppressionStateFromSelectedRow(out SonarCompositeRuleId ruleId, out bool isSuppressed)
+ {
+ SonarCompositeRuleId ruleIdOut = null;
+ var isSuppressedOut = false;
+ var result = vSServiceOperation.Execute(errorList =>
{
- ruleId = null;
- if (!handle.TryGetSnapshot(out var snapshot, out var index))
+ if (!TryGetSelectedTableEntry(errorList, out var handle) || !TryGetRuleId(handle, out ruleIdOut))
{
return false;
}
- var errorCode = FindErrorCodeForEntry(snapshot, index);
- return SonarCompositeRuleId.TryParse(errorCode, out ruleId);
- }
+ isSuppressedOut = IsSuppressed(handle);
+ return true;
+ });
- public bool TryGetRuleIdAndSuppressionStateFromSelectedRow(out SonarCompositeRuleId ruleId, out bool isSuppressed)
- {
- SonarCompositeRuleId ruleIdOut = null;
- var isSuppressedOut = false;
- var result = vSServiceOperation.Execute(errorList =>
- {
- if (!TryGetSelectedTableEntry(errorList, out var handle) || !TryGetRuleId(handle, out ruleIdOut))
- {
- return false;
- }
+ ruleId = ruleIdOut;
+ isSuppressed = isSuppressedOut;
- isSuppressedOut = IsSuppressed(handle);
- return true;
- });
+ return result;
+ }
- ruleId = ruleIdOut;
- isSuppressed = isSuppressedOut;
+ public bool TryGetIssueFromSelectedRow(out IFilterableIssue issue)
+ {
+ IFilterableIssue issueOut = null;
+ var result = vSServiceOperation.Execute(
+ errorList => TryGetSelectedTableEntry(errorList, out var handle) && TryGetFilterableIssue(handle, out issueOut));
- return result;
- }
+ issue = issueOut;
- public bool TryGetIssueFromSelectedRow(out IFilterableIssue issue)
- {
- IFilterableIssue issueOut = null;
- var result = vSServiceOperation.Execute(
- errorList => TryGetSelectedTableEntry(errorList, out var handle) && TryGetFilterableIssue(handle, out issueOut));
+ return result;
+ }
+
+ public bool TryGetFilterableIssue(ITableEntryHandle handle, out IFilterableIssue issue)
+ {
+ IFilterableIssue issueOut = null;
+ var result = vSServiceOperation.Execute(
+ _ => handle.TryGetSnapshot(out var snapshot, out var index)
+ && TryGetValue(snapshot, index, SonarLintTableControlConstants.IssueVizColumnName, out issueOut));
- issue = issueOut;
+ issue = issueOut;
- return result;
- }
+ return result;
+ }
+
+ public bool TryGetRoslynIssueFromSelectedRow(out IFilterableRoslynIssue filterableRoslynIssue)
+ {
+ IFilterableRoslynIssue outIssue = null;
- public bool TryGetFilterableIssue(ITableEntryHandle handle, out IFilterableIssue issue)
+ var result = vSServiceOperation.Execute(errorList =>
{
- IFilterableIssue issueOut = null;
- var result = vSServiceOperation.Execute(
- _ => handle.TryGetSnapshot(out var snapshot, out var index)
- && TryGetValue(snapshot, index, SonarLintTableControlConstants.IssueVizColumnName, out issueOut));
+ string errorCode;
+ if (TryGetSelectedSnapshotAndIndex(errorList, out var snapshot, out var index)
+ && (errorCode = FindErrorCodeForEntry(snapshot, index)) != null
+ && TryGetValue(snapshot, index, StandardTableKeyNames.DocumentName, out string filePath)
+ && TryGetValue(snapshot, index, StandardTableKeyNames.Line, out int line)
+ && TryGetValue(snapshot, index, StandardTableKeyNames.Column, out int column))
+ {
+ outIssue = new FilterableRoslynIssue(errorCode, filePath, line + 1, column + 1 /* error list issues are 0-based and we use 1-based line & column numbers */);
+ }
- issue = issueOut;
+ return outIssue != null;
+ });
- return result;
- }
+ filterableRoslynIssue = outIssue;
- public bool TryGetRoslynIssueFromSelectedRow(out IFilterableRoslynIssue filterableRoslynIssue)
- {
- IFilterableRoslynIssue outIssue = null;
+ return result;
+ }
- var result = vSServiceOperation.Execute(errorList =>
- {
- string errorCode;
- if (TryGetSelectedSnapshotAndIndex(errorList, out var snapshot, out var index)
- && (errorCode = FindErrorCodeForEntry(snapshot, index)) != null
- && TryGetValue(snapshot, index, StandardTableKeyNames.DocumentName, out string filePath)
- && TryGetValue(snapshot, index, StandardTableKeyNames.Line, out int line)
- && TryGetValue(snapshot, index, StandardTableKeyNames.Column, out int column))
- {
- outIssue = new FilterableRoslynIssue(errorCode, filePath, line + 1, column + 1 /* error list issues are 0-based and we use 1-based line & column numbers */);
- }
-
- return outIssue != null;
- });
-
- filterableRoslynIssue = outIssue;
-
- return result;
- }
+ private static bool IsSuppressed(ITableEntryHandle handle) =>
+ handle.TryGetSnapshot(out var snapshot, out var index)
+ && TryGetValue(snapshot, index, StandardTableKeyNames.SuppressionState, out SuppressionState suppressionState)
+ && suppressionState == SuppressionState.Suppressed;
- private static bool IsSuppressed(ITableEntryHandle handle)
+ private static string FindErrorCodeForEntry(ITableEntriesSnapshot snapshot, int index)
+ {
+ if (!TryGetValue(snapshot, index, StandardTableKeyNames.ErrorCode, out string errorCode))
{
- return handle.TryGetSnapshot(out var snapshot, out var index)
- && TryGetValue(snapshot, index, StandardTableKeyNames.SuppressionState, out SuppressionState suppressionState)
- && suppressionState == SuppressionState.Suppressed;
+ return null;
}
- private static string FindErrorCodeForEntry(ITableEntriesSnapshot snapshot, int index)
+ if (TryGetValue(snapshot, index, StandardTableKeyNames.BuildTool, out string buildTool))
{
- if (!TryGetValue(snapshot, index, StandardTableKeyNames.ErrorCode, out string errorCode))
+ // For CSharp and VisualBasic the buildTool returns the name of the analyzer package.
+ // The prefix is required for roslyn languages as the error code is in style "S111" meaning
+ // unlike other languages it has no repository prefix.
+ return buildTool switch
{
- return null;
- }
+ "SonarAnalyzer.CSharp" => $"{SonarRuleRepoKeys.CSharpRules}:{errorCode}",
+ "SonarAnalyzer.VisualBasic" => $"{SonarRuleRepoKeys.VBNetRules}:{errorCode}",
+ "SonarLint" => errorCode,
+ _ => null
+ };
+ }
- if (TryGetValue(snapshot, index, StandardTableKeyNames.BuildTool, out string buildTool))
+ if (TryGetValue(snapshot, index, StandardTableKeyNames.HelpLink, out string helpLink))
+ {
+ if (helpLink.Contains("rules.sonarsource.com/csharp/"))
{
- // For CSharp and VisualBasic the buildTool returns the name of the analyzer package.
- // The prefix is required for roslyn languages as the error code is in style "S111" meaning
- // unlike other languages it has no repository prefix.
- return buildTool switch
- {
- "SonarAnalyzer.CSharp" => $"{SonarRuleRepoKeys.CSharpRules}:{errorCode}",
- "SonarAnalyzer.VisualBasic" => $"{SonarRuleRepoKeys.VBNetRules}:{errorCode}",
- "SonarLint" => errorCode,
- _ => null
- };
+ return $"{SonarRuleRepoKeys.CSharpRules}:{errorCode}";
}
- if (TryGetValue(snapshot, index, StandardTableKeyNames.HelpLink, out string helpLink))
+ if (helpLink.Contains("rules.sonarsource.com/vbnet/"))
{
- if (helpLink.Contains("rules.sonarsource.com/csharp/"))
- {
- return $"{SonarRuleRepoKeys.CSharpRules}:{errorCode}";
- }
-
- if (helpLink.Contains("rules.sonarsource.com/vbnet/"))
- {
- return $"{SonarRuleRepoKeys.VBNetRules}:{errorCode}";
- }
+ return $"{SonarRuleRepoKeys.VBNetRules}:{errorCode}";
}
-
- return null;
}
- private static bool TryGetSelectedSnapshotAndIndex(IErrorList errorList, out ITableEntriesSnapshot snapshot, out int index)
- {
- snapshot = default;
- index = default;
+ return null;
+ }
- return TryGetSelectedTableEntry(errorList, out var handle) && handle.TryGetSnapshot(out snapshot, out index);
- }
+ private static bool TryGetSelectedSnapshotAndIndex(IErrorList errorList, out ITableEntriesSnapshot snapshot, out int index)
+ {
+ snapshot = default;
+ index = default;
- private static bool TryGetSelectedTableEntry(IErrorList errorList, out ITableEntryHandle handle)
- {
- handle = null;
+ return TryGetSelectedTableEntry(errorList, out var handle) && handle.TryGetSnapshot(out snapshot, out index);
+ }
- var selectedItems = errorList?.TableControl?.SelectedEntries;
+ private static bool TryGetSelectedTableEntry(IErrorList errorList, out ITableEntryHandle handle)
+ {
+ handle = null;
- if (selectedItems == null)
- {
- return false;
- }
+ var selectedItems = errorList?.TableControl?.SelectedEntries;
- foreach (var tableEntryHandle in selectedItems)
- {
- if (handle != null)
- {
- return false; // more than one selected is not supported
- }
+ if (selectedItems == null)
+ {
+ return false;
+ }
- handle = tableEntryHandle;
+ foreach (var tableEntryHandle in selectedItems)
+ {
+ if (handle != null)
+ {
+ return false; // more than one selected is not supported
}
- return true;
+ handle = tableEntryHandle;
}
- private static bool TryGetValue(
- ITableEntriesSnapshot snapshot,
- int index,
- string columnName,
- out T value)
- {
- value = default;
+ return true;
+ }
- try
- {
- if (!snapshot.TryGetValue(index, columnName, out var objValue) || objValue == null)
- {
- return false;
- }
+ private static bool TryGetValue(
+ ITableEntriesSnapshot snapshot,
+ int index,
+ string columnName,
+ out T value)
+ {
+ value = default;
- value = (T)objValue;
- return true;
- }
- catch (InvalidCastException)
+ try
+ {
+ if (!snapshot.TryGetValue(index, columnName, out var objValue) || objValue == null)
{
return false;
}
+
+ value = (T)objValue;
+ return true;
+ }
+ catch (InvalidCastException)
+ {
+ return false;
}
}
}
diff --git a/src/IssueViz.UnitTests/Models/AnalysisIssueVisualizationTests.cs b/src/IssueViz.UnitTests/Models/AnalysisIssueVisualizationTests.cs
index 93dab60f9..de2516e8d 100644
--- a/src/IssueViz.UnitTests/Models/AnalysisIssueVisualizationTests.cs
+++ b/src/IssueViz.UnitTests/Models/AnalysisIssueVisualizationTests.cs
@@ -18,248 +18,192 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-using System;
using System.ComponentModel;
-using FluentAssertions;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.VisualStudio.Text;
-using Moq;
using SonarLint.VisualStudio.Core.Analysis;
using SonarLint.VisualStudio.Core.Suppressions;
using SonarLint.VisualStudio.IssueVisualization.Models;
-namespace SonarLint.VisualStudio.IssueVisualization.UnitTests.Models
+namespace SonarLint.VisualStudio.IssueVisualization.UnitTests.Models;
+
+[TestClass]
+public class AnalysisIssueVisualizationTests
{
- [TestClass]
- public class AnalysisIssueVisualizationTests
- {
- [TestMethod]
- public void Ctor_StepNumberIsZero()
- {
- var testSubject = CreateTestSubject();
-
- testSubject.StepNumber.Should().Be(0);
- }
-
- [TestMethod]
- public void Ctor_InitialFilePathIsTakenFromIssue()
- {
- var testSubject = CreateTestSubject(filePath: "test path");
-
- testSubject.CurrentFilePath.Should().Be("test path");
- }
-
- [TestMethod]
- public void Ctor_NullSpan_InitialSpanIsSetToGivenValue()
- {
- var testSubject = CreateTestSubject(span: null);
-
- testSubject.Span.Should().BeNull();
- }
-
- [TestMethod]
- public void Ctor_EmptySpan_InitialSpanIsSetToGivenValue()
- {
- var span = new SnapshotSpan();
- var testSubject = CreateTestSubject(span: span);
-
- testSubject.Span.Should().Be(span);
- }
-
- [TestMethod]
- public void Ctor_NonEmptySpan_InitialSpanIsSetToGivenValue()
- {
- var span = CreateSpan();
- var testSubject = CreateTestSubject(span: span);
-
- testSubject.Span.Should().Be(span);
- }
-
- [TestMethod]
- public void Location_ReturnsUnderlyingIssueLocation()
- {
- var testSubject = CreateTestSubject();
- testSubject.Location.Should().Be(testSubject.Issue.PrimaryLocation);
- }
-
- [TestMethod]
- public void SetCurrentFilePath_FilePathIsNull_SpanIsInvalidated()
- {
- // Arrange
- var oldFilePath = "oldpath.txt";
- var oldSpan = CreateSpan();
-
- var testSubject = CreateTestSubject(oldFilePath, oldSpan);
- testSubject.Span.Should().Be(oldSpan);
- testSubject.CurrentFilePath.Should().Be(oldFilePath);
-
- var propertyChangedEventHandler = new Mock();
- testSubject.PropertyChanged += propertyChangedEventHandler.Object;
+ private readonly SnapshotSpan emptySpan = new();
+ private readonly string filePath = "filePath.txt";
- // Act
- testSubject.CurrentFilePath = null;
+ private IAnalysisIssue issue = Substitute.For();
+ private AnalysisIssueVisualization issueVisualizationWithEmptySpan;
+ private AnalysisIssueVisualization issueVisualizationWithNoSpan;
+ private AnalysisIssueVisualization issueVisualizationWithNotEmptySpan;
+ private SnapshotSpan notEmptySpan;
- // Assert
- testSubject.Span.Value.IsEmpty.Should().BeTrue();
- testSubject.CurrentFilePath.Should().BeNull();
+ [TestInitialize]
+ public void TestInitialize()
+ {
+ notEmptySpan = CreateSpan();
+ issue = Substitute.For();
+ MockAnalysisIssue();
- VerifyPropertyChangedRaised(propertyChangedEventHandler, nameof(testSubject.CurrentFilePath));
- VerifyPropertyChangedRaised(propertyChangedEventHandler, nameof(testSubject.Span));
- propertyChangedEventHandler.VerifyNoOtherCalls();
- }
+ issueVisualizationWithNoSpan = new AnalysisIssueVisualization(null, issue, null, null);
+ issueVisualizationWithEmptySpan = new AnalysisIssueVisualization(null, issue, emptySpan, null);
+ issueVisualizationWithNotEmptySpan = new AnalysisIssueVisualization(null, issue, notEmptySpan, null);
+ }
- [TestMethod]
- public void SetCurrentFilePath_FilePathIsNotNull_SpanNotChanged()
- {
- // Arrange
- var oldFilePath = "oldpath.txt";
- var oldSpan = CreateSpan();
+ [TestMethod]
+ public void Ctor_StepNumberIsZero() => issueVisualizationWithNoSpan.StepNumber.Should().Be(0);
- var testSubject = CreateTestSubject(oldFilePath, oldSpan);
- testSubject.Span.Should().Be(oldSpan);
- testSubject.CurrentFilePath.Should().Be(oldFilePath);
+ [TestMethod]
+ public void Ctor_InitialFilePathIsTakenFromIssue() => issueVisualizationWithNoSpan.CurrentFilePath.Should().Be(filePath);
- var propertyChangedEventHandler = new Mock();
- testSubject.PropertyChanged += propertyChangedEventHandler.Object;
+ [TestMethod]
+ public void Ctor_NullSpan_InitialSpanIsSetToGivenValue() => issueVisualizationWithNoSpan.Span.Should().BeNull();
- // Act
- testSubject.CurrentFilePath = "newpath.txt";
+ [TestMethod]
+ public void Ctor_EmptySpan_InitialSpanIsSetToGivenValue() => issueVisualizationWithEmptySpan.Span.Should().Be(emptySpan);
- // Assert
- testSubject.Span.Should().Be(oldSpan);
- testSubject.CurrentFilePath.Should().Be("newpath.txt");
+ [TestMethod]
+ public void Ctor_NonEmptySpan_InitialSpanIsSetToGivenValue() => issueVisualizationWithNotEmptySpan.Span.Should().Be(notEmptySpan);
- VerifyPropertyChangedRaised(propertyChangedEventHandler, nameof(testSubject.CurrentFilePath));
- VerifyPropertyChangedNotRaised(propertyChangedEventHandler, nameof(testSubject.Span));
- propertyChangedEventHandler.VerifyNoOtherCalls();
- }
+ [TestMethod]
+ public void Location_ReturnsUnderlyingIssueLocation() => issueVisualizationWithEmptySpan.Location.Should().Be(issueVisualizationWithEmptySpan.Issue.PrimaryLocation);
- [TestMethod]
- public void SetCurrentFilePath_NoSubscribers_NoException()
- {
- var testSubject = CreateTestSubject();
+ [TestMethod]
+ public void SetCurrentFilePath_FilePathIsNull_SpanIsInvalidated()
+ {
+ VerifySpanAndLocationCorrect(filePath);
+ var propertyChangedEventHandler = MockSubscriberToPropertyChanged();
- Action act = () => testSubject.CurrentFilePath = "new path";
- act.Should().NotThrow();
+ issueVisualizationWithNotEmptySpan.CurrentFilePath = null;
- testSubject.CurrentFilePath.Should().Be("new path");
- }
+ issueVisualizationWithNotEmptySpan.Span.Value.IsEmpty.Should().BeTrue();
+ issueVisualizationWithNotEmptySpan.CurrentFilePath.Should().BeNull();
+ VerifyPropertyChangedRaised(propertyChangedEventHandler, issueVisualizationWithNotEmptySpan, nameof(issueVisualizationWithNotEmptySpan.CurrentFilePath));
+ VerifyPropertyChangedRaised(propertyChangedEventHandler, issueVisualizationWithNotEmptySpan, nameof(issueVisualizationWithNotEmptySpan.Span));
+ propertyChangedEventHandler.ReceivedCalls().Count().Should().Be(2);
+ }
- [TestMethod]
- public void SetCurrentFilePath_HasSubscribers_NotifiesSubscribers()
- {
- var propertyChangedEventHandler = new Mock();
+ [TestMethod]
+ public void SetCurrentFilePath_FilePathIsNotNull_SpanNotChanged()
+ {
+ VerifySpanAndLocationCorrect(filePath);
+ var propertyChangedEventHandler = MockSubscriberToPropertyChanged();
- var testSubject = CreateTestSubject();
- testSubject.PropertyChanged += propertyChangedEventHandler.Object;
+ issueVisualizationWithNotEmptySpan.CurrentFilePath = "newpath.txt";
- testSubject.CurrentFilePath = "new path";
+ issueVisualizationWithNotEmptySpan.Span.Should().Be(notEmptySpan);
+ issueVisualizationWithNotEmptySpan.CurrentFilePath.Should().Be("newpath.txt");
+ VerifyPropertyChangedRaised(propertyChangedEventHandler, issueVisualizationWithNotEmptySpan, nameof(issueVisualizationWithNotEmptySpan.CurrentFilePath));
+ VerifyPropertyChangedNotRaised(propertyChangedEventHandler, nameof(issueVisualizationWithNotEmptySpan.Span));
+ propertyChangedEventHandler.ReceivedCalls().Count().Should().Be(1);
+ }
- VerifyPropertyChangedRaised(propertyChangedEventHandler, nameof(testSubject.CurrentFilePath));
- propertyChangedEventHandler.VerifyNoOtherCalls();
-
- testSubject.CurrentFilePath.Should().Be("new path");
- }
-
- [TestMethod]
- public void SetSpan_NoSubscribers_NoException()
- {
- var newSpan = CreateSpan();
- var testSubject = CreateTestSubject();
-
- Action act = () => testSubject.Span = newSpan;
- act.Should().NotThrow();
-
- testSubject.Span.Should().Be(newSpan);
- }
-
- [TestMethod]
- public void SetSpan_HasSubscribers_NotifiesSubscribers()
- {
- var newSpan = CreateSpan();
- var propertyChangedEventHandler = new Mock();
+ [TestMethod]
+ public void SetCurrentFilePath_NoSubscribers_NoException()
+ {
+ Action act = () => issueVisualizationWithNotEmptySpan.CurrentFilePath = "new path";
+ act.Should().NotThrow();
- var testSubject = CreateTestSubject();
- testSubject.PropertyChanged += propertyChangedEventHandler.Object;
+ issueVisualizationWithNotEmptySpan.CurrentFilePath.Should().Be("new path");
+ }
- testSubject.Span = newSpan;
+ [TestMethod]
+ public void SetCurrentFilePath_HasSubscribers_NotifiesSubscribers()
+ {
+ var propertyChangedEventHandler = MockSubscriberToPropertyChanged();
- VerifyPropertyChangedRaised(propertyChangedEventHandler, nameof(testSubject.Span));
- propertyChangedEventHandler.VerifyNoOtherCalls();
+ issueVisualizationWithNotEmptySpan.CurrentFilePath = "new path";
- testSubject.Span.Should().Be(newSpan);
- }
+ VerifyPropertyChangedRaised(propertyChangedEventHandler, issueVisualizationWithNotEmptySpan, nameof(issueVisualizationWithNotEmptySpan.CurrentFilePath));
+ propertyChangedEventHandler.ReceivedCalls().Count().Should().Be(1);
+ issueVisualizationWithNotEmptySpan.CurrentFilePath.Should().Be("new path");
+ }
- [TestMethod]
- public void SetIsSuppressed_HasSubscribers_VerifyRaised()
- {
- var testSubject = CreateTestSubject();
+ [TestMethod]
+ public void SetSpan_NoSubscribers_NoException()
+ {
+ var newSpan = CreateSpan();
- testSubject.IsSuppressed.Should().BeFalse();
+ Action act = () => issueVisualizationWithNotEmptySpan.Span = newSpan;
+ act.Should().NotThrow();
- var propertyChangedEventHandler = new Mock();
- testSubject.PropertyChanged += propertyChangedEventHandler.Object;
+ issueVisualizationWithNotEmptySpan.Span.Should().Be(newSpan);
+ }
- testSubject.IsSuppressed = true;
+ [TestMethod]
+ public void SetSpan_HasSubscribers_NotifiesSubscribers()
+ {
+ var newSpan = CreateSpan();
+ var propertyChangedEventHandler = MockSubscriberToPropertyChanged();
- VerifyPropertyChangedRaised(propertyChangedEventHandler, nameof(testSubject.IsSuppressed));
- propertyChangedEventHandler.VerifyNoOtherCalls();
+ issueVisualizationWithNotEmptySpan.Span = newSpan;
- testSubject.IsSuppressed.Should().BeTrue();
- }
+ VerifyPropertyChangedRaised(propertyChangedEventHandler, issueVisualizationWithNotEmptySpan, nameof(issueVisualizationWithNotEmptySpan.Span));
+ propertyChangedEventHandler.ReceivedCalls().Count().Should().Be(1);
+ issueVisualizationWithNotEmptySpan.Span.Should().Be(newSpan);
+ }
- [TestMethod]
- public void IsFilterable()
- {
- var id = Guid.NewGuid();
- var issueMock = new Mock();
- issueMock.SetupGet(x => x.Id).Returns(id);
- issueMock.SetupGet(x => x.RuleKey).Returns("my key");
- issueMock.SetupGet(x => x.PrimaryLocation.FilePath).Returns("x:\\aaa.foo");
- issueMock.SetupGet(x => x.PrimaryLocation.TextRange.StartLine).Returns(999);
- issueMock.SetupGet(x => x.PrimaryLocation.TextRange.LineHash).Returns("hash");
+ [TestMethod]
+ public void SetIsSuppressed_HasSubscribers_VerifyRaised()
+ {
+ issueVisualizationWithNotEmptySpan.IsSuppressed.Should().BeFalse();
+ var propertyChangedEventHandler = MockSubscriberToPropertyChanged();
- var testSubject = new AnalysisIssueVisualization(null, issueMock.Object, new SnapshotSpan(), null);
+ issueVisualizationWithNotEmptySpan.IsSuppressed = true;
- testSubject.Should().BeAssignableTo();
+ VerifyPropertyChangedRaised(propertyChangedEventHandler, issueVisualizationWithNotEmptySpan, nameof(issueVisualizationWithNotEmptySpan.IsSuppressed));
+ propertyChangedEventHandler.ReceivedCalls().Count().Should().Be(1);
+ issueVisualizationWithNotEmptySpan.IsSuppressed.Should().BeTrue();
+ }
- var filterable = (IFilterableIssue)testSubject;
+ [TestMethod]
+ public void IsFilterable()
+ {
+ issueVisualizationWithEmptySpan.Should().BeAssignableTo();
+
+ var filterable = (IFilterableIssue)issueVisualizationWithEmptySpan;
+ filterable.IssueId.Should().Be(issue.Id);
+ filterable.RuleId.Should().Be(issue.RuleKey);
+ filterable.FilePath.Should().Be(issue.PrimaryLocation.FilePath);
+ filterable.StartLine.Should().Be(issue.PrimaryLocation.TextRange.StartLine);
+ filterable.LineHash.Should().Be(issue.PrimaryLocation.TextRange.LineHash);
+ }
- filterable.IssueId.Should().Be(id);
- filterable.RuleId.Should().Be(issueMock.Object.RuleKey);
- filterable.FilePath.Should().Be(issueMock.Object.PrimaryLocation.FilePath);
- filterable.StartLine.Should().Be(issueMock.Object.PrimaryLocation.TextRange.StartLine);
- filterable.LineHash.Should().Be(issueMock.Object.PrimaryLocation.TextRange.LineHash);
- }
+ private void MockAnalysisIssue()
+ {
+ var id = Guid.NewGuid();
+ issue.Id.Returns(id);
+ issue.RuleKey.Returns("my key");
+ issue.PrimaryLocation.FilePath.Returns("x:\\aaa.foo");
+ issue.PrimaryLocation.TextRange.StartLine.Returns(999);
+ issue.PrimaryLocation.TextRange.LineHash.Returns("hash");
+ issue.PrimaryLocation.FilePath.Returns(filePath);
+ }
- private SnapshotSpan CreateSpan()
- {
- var mockTextSnapshot = new Mock();
- mockTextSnapshot.SetupGet(x => x.Length).Returns(20);
+ private SnapshotSpan CreateSpan()
+ {
+ var mockTextSnapshot = Substitute.For();
+ mockTextSnapshot.Length.Returns(20);
- return new SnapshotSpan(mockTextSnapshot.Object, new Span(0, 10));
- }
+ return new SnapshotSpan(mockTextSnapshot, new Span(0, 10));
+ }
- private AnalysisIssueVisualization CreateTestSubject(string filePath = null, SnapshotSpan? span = null)
- {
- var issue = new Mock();
- issue.SetupGet(x => x.PrimaryLocation.FilePath).Returns(filePath);
+ private void VerifyPropertyChangedRaised(PropertyChangedEventHandler propertyChangedEventHandler, AnalysisIssueVisualization testSubject, string propertyName) =>
+ propertyChangedEventHandler.Received().Invoke(testSubject, Arg.Is(x => x.PropertyName == propertyName));
- return new AnalysisIssueVisualization(null, issue.Object, span, null);
- }
+ private void VerifyPropertyChangedNotRaised(PropertyChangedEventHandler propertyChangedEventHandler, string propertyName) =>
+ propertyChangedEventHandler.DidNotReceive().Invoke(Arg.Any