Skip to content

Commit

Permalink
SLVS-1598 Use getEffectiveIssueDetails for issues with SLCore id inst…
Browse files Browse the repository at this point in the history
…ead of getEffectiveRuleDetails (#5830)
  • Loading branch information
gabriela-trutan-sonarsource authored Nov 14, 2024
1 parent 66a7607 commit 1fad501
Show file tree
Hide file tree
Showing 31 changed files with 968 additions and 387 deletions.
1 change: 1 addition & 0 deletions src/ConnectedMode.UnitTests/TestFilterableIssue.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ namespace SonarLint.VisualStudio.ConnectedMode.UnitTests;

internal class TestFilterableIssue : IFilterableIssue
{
public Guid? IssueId { get; set; }
public string RuleId { get; set; }
public string LineHash { get; set; }
public int? StartLine { get; set; }
Expand Down
5 changes: 4 additions & 1 deletion src/Core/IEducation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

using SonarLint.VisualStudio.Core.Suppressions;

namespace SonarLint.VisualStudio.Core
{
/// <summary>
Expand All @@ -32,6 +34,7 @@ public interface IEducation
/// be displayed in the IDE. Otherwise, the rule help will be displayed in the
/// browser i.e. at rules.sonarsource.com</remarks>
/// <param name="issueContext">Key for the How to fix it Context acquired from a specific issue. Can be null.</param>
void ShowRuleHelp(SonarCompositeRuleId ruleId, string issueContext);
/// <param name="issueId">The SlCore issue ID for which the rule help should be shown.s</param>
void ShowRuleHelp(SonarCompositeRuleId ruleId, Guid? issueId, string issueContext);
}
}
4 changes: 4 additions & 0 deletions src/Core/Suppressions/FilterableRoslynIssue.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ public FilterableRoslynIssue(string ruleId, string filePath, int startLine, int
RoslynStartColumn = startColumn;
}

/// <summary>
/// Always null, as this Id is specific to SlCore
/// </summary>
public Guid? IssueId => null;
public string RuleId { get; }
public string FilePath { get; }
public int? StartLine => RoslynStartLine;
Expand Down
5 changes: 5 additions & 0 deletions src/Core/Suppressions/IFilterableIssue.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ namespace SonarLint.VisualStudio.Core.Suppressions
/// </summary>
public interface IFilterableIssue
{
/// <summary>
/// The id of the issue that comes from SlCore
/// Nullable due to the fact that some issues do not come from SlCore (e.g. Roslyn)
/// </summary>
Guid? IssueId { get; }
string RuleId { get; }
string FilePath { get; }
string LineHash { get; }
Expand Down
51 changes: 34 additions & 17 deletions src/Education.UnitTests/EducationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,10 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

using System;
using System.Threading;
using System.Windows.Documents;
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using SonarLint.VisualStudio.Core;
using SonarLint.VisualStudio.Education.Commands;
using SonarLint.VisualStudio.Core.Suppressions;
using SonarLint.VisualStudio.Education.Rule;
using SonarLint.VisualStudio.Education.XamlGenerator;
using SonarLint.VisualStudio.TestInfrastructure;
Expand Down Expand Up @@ -53,11 +49,11 @@ public void ShowRuleHelp_KnownRule_DocumentIsDisplayedInToolWindow()
var ruleId = new SonarCompositeRuleId("repoKey", "ruleKey");

var ruleInfo = Mock.Of<IRuleInfo>();
ruleMetaDataProvider.Setup(x => x.GetRuleInfoAsync(It.IsAny<SonarCompositeRuleId>())).ReturnsAsync(ruleInfo);
ruleMetaDataProvider.Setup(x => x.GetRuleInfoAsync(It.IsAny<SonarCompositeRuleId>(), It.IsAny<Guid?>())).ReturnsAsync(ruleInfo);

var flowDocument = Mock.Of<FlowDocument>();
var ruleHelpXamlBuilder = new Mock<IRuleHelpXamlBuilder>();
ruleHelpXamlBuilder.Setup(x => x.Create(ruleInfo, /* todo */ null)).Returns(flowDocument);
ruleHelpXamlBuilder.Setup(x => x.Create(ruleInfo, /* todo by SLVS-1630 */ null)).Returns(flowDocument);

var ruleDescriptionToolWindow = new Mock<IRuleHelpToolWindow>();

Expand All @@ -74,10 +70,10 @@ public void ShowRuleHelp_KnownRule_DocumentIsDisplayedInToolWindow()
toolWindowService.Invocations.Should().HaveCount(0);

// Act
testSubject.ShowRuleHelp(ruleId, null);
testSubject.ShowRuleHelp(ruleId, null, null);

ruleMetaDataProvider.Verify(x => x.GetRuleInfoAsync(ruleId), Times.Once);
ruleHelpXamlBuilder.Verify(x => x.Create(ruleInfo, /* todo */ null), Times.Once);
ruleMetaDataProvider.Verify(x => x.GetRuleInfoAsync(ruleId, It.IsAny<Guid?>()), 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);

Expand All @@ -95,9 +91,9 @@ public void ShowRuleHelp_FailedToDisplayRule_RuleIsShownInBrowser()
var ruleId = new SonarCompositeRuleId("repoKey", "ruleKey");

var ruleInfo = Mock.Of<IRuleInfo>();
ruleMetadataProvider.Setup(x => x.GetRuleInfoAsync(It.IsAny<SonarCompositeRuleId>())).ReturnsAsync(ruleInfo);
ruleMetadataProvider.Setup(x => x.GetRuleInfoAsync(It.IsAny<SonarCompositeRuleId>(), It.IsAny<Guid?>())).ReturnsAsync(ruleInfo);

ruleHelpXamlBuilder.Setup(x => x.Create(ruleInfo, /* todo */ null)).Throws(new Exception("some layout error"));
ruleHelpXamlBuilder.Setup(x => x.Create(ruleInfo, /* todo by SLVS-1630 */ null)).Throws(new Exception("some layout error"));

var testSubject = CreateEducation(
toolWindowService.Object,
Expand All @@ -107,9 +103,9 @@ public void ShowRuleHelp_FailedToDisplayRule_RuleIsShownInBrowser()

toolWindowService.Reset(); // Called in the constructor, so need to reset to clear the list of invocations

testSubject.ShowRuleHelp(ruleId, /* todo */ null);
testSubject.ShowRuleHelp(ruleId, null, /* todo by SLVS-1630 */null);

ruleMetadataProvider.Verify(x => x.GetRuleInfoAsync(ruleId), Times.Once);
ruleMetadataProvider.Verify(x => x.GetRuleInfoAsync(ruleId, It.IsAny<Guid?>()), Times.Once);
showRuleInBrowser.Verify(x => x.ShowRuleDescription(ruleId), Times.Once);

// should have attempted to build the rule, but failed
Expand All @@ -126,7 +122,7 @@ public void ShowRuleHelp_UnknownRule_RuleIsShownInBrowser()
var showRuleInBrowser = new Mock<IShowRuleInBrowser>();

var unknownRule = new SonarCompositeRuleId("known", "xxx");
ruleMetadataProvider.Setup(x => x.GetRuleInfoAsync(unknownRule)).ReturnsAsync((IRuleInfo)null);
ruleMetadataProvider.Setup(x => x.GetRuleInfoAsync(unknownRule, It.IsAny<Guid?>())).ReturnsAsync((IRuleInfo)null);

var testSubject = CreateEducation(
toolWindowService.Object,
Expand All @@ -136,16 +132,37 @@ public void ShowRuleHelp_UnknownRule_RuleIsShownInBrowser()

toolWindowService.Reset(); // Called in the constructor, so need to reset to clear the list of invocations

testSubject.ShowRuleHelp(unknownRule, /* todo */ null);
testSubject.ShowRuleHelp(unknownRule, null, /* todo by SLVS-1630 */ null);

ruleMetadataProvider.Verify(x => x.GetRuleInfoAsync(unknownRule), Times.Once);
ruleMetadataProvider.Verify(x => x.GetRuleInfoAsync(unknownRule, It.IsAny<Guid?>()), 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<IToolWindowService>();
var ruleMetadataProvider = new Mock<IRuleMetaDataProvider>();
var ruleHelpXamlBuilder = new Mock<IRuleHelpXamlBuilder>();
var showRuleInBrowser = new Mock<IShowRuleInBrowser>();
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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,10 @@
* 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.Core.Suppressions;
using SonarLint.VisualStudio.Education.SonarLint.VisualStudio.Education.ErrorList;
using SonarLint.VisualStudio.Infrastructure.VS;
using SonarLint.VisualStudio.TestInfrastructure;
Expand Down Expand Up @@ -68,10 +67,30 @@ public void PreprocessNavigateToHelp_IsASonarRule_EventIsHandledAndEducationServ

errorListHelper.Verify(x => x.TryGetRuleId(handle, out ruleId));
education.Invocations.Should().HaveCount(1);
education.Verify(x => x.ShowRuleHelp(ruleId, /* todo */ null));
education.Verify(x => x.ShowRuleHelp(ruleId, null, /* todo by SLVS-1630 */ null));
eventArgs.Handled.Should().BeTrue();
}

[TestMethod]
[DataRow(true)]
[DataRow(false)]
public void PreprocessNavigateToHelp_IsASonarRule_EducationServiceIsCalledWithIssueId(bool getFilterableIssueResult)
{
SonarCompositeRuleId ruleId;
IFilterableIssue filterableIssue = new Mock<IFilterableIssue>().Object;
SonarCompositeRuleId.TryParse("cpp:S123", out ruleId);
var handle = Mock.Of<ITableEntryHandle>();
var errorListHelper = CreateErrorListHelper(isSonarRule: true, ruleId);
errorListHelper.Setup(x => x.TryGetFilterableIssue(It.IsAny<ITableEntryHandle>(), out filterableIssue)).Returns(getFilterableIssueResult);
var education = new Mock<IEducation>();
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<IErrorListHelper> CreateErrorListHelper(bool isSonarRule, SonarCompositeRuleId ruleId)
{
var mock = new Mock<IErrorListHelper>();
Expand Down
Loading

0 comments on commit 1fad501

Please sign in to comment.