Skip to content

Commit

Permalink
SLVS-1625 CaYC: Replace Moq with Nsubstitute (#5836)
Browse files Browse the repository at this point in the history
  • Loading branch information
1 parent 98ab2fb commit 9ba426c
Show file tree
Hide file tree
Showing 14 changed files with 1,175 additions and 1,407 deletions.
7 changes: 6 additions & 1 deletion SonarLint.VisualStudio.Integration.sln.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -132,4 +132,9 @@
<s:String x:Key="/Default/CodeStyle/Generate/=Implementations/Options/=Async/@EntryIndexedValue">False</s:String>
<s:String x:Key="/Default/CodeStyle/Generate/=Implementations/Options/=Mutable/@EntryIndexedValue">False</s:String>
<s:Boolean x:Key="/Default/CodeStyle/Naming/CSharpAutoNaming/IsNotificationDisabled/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Dpa/IsNoEtwHostNotificationEnabled/@EntryValue">False</s:Boolean></wpf:ResourceDictionary>
<s:Boolean x:Key="/Default/Dpa/IsNoEtwHostNotificationEnabled/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpUseContinuousIndentInsideBracesMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002EMemberReordering_002EMigrations_002ECSharpFileLayoutPatternRemoveIsAttributeUpgrade/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
282 changes: 132 additions & 150 deletions src/Education.UnitTests/EducationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<IToolWindowService>();
ruleMetadataProvider = Substitute.For<IRuleMetaDataProvider>();
showRuleInBrowser = Substitute.For<IShowRuleInBrowser>();
ruleHelpXamlBuilder = Substitute.For<IRuleHelpXamlBuilder>();
ruleDescriptionToolWindow = Substitute.For<IRuleHelpToolWindow>();
ruleInfo = Substitute.For<IRuleInfo>();
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<Education, IEducation>(
MefTestHelpers.CreateExport<IToolWindowService>(),
MefTestHelpers.CreateExport<IRuleMetaDataProvider>(),
MefTestHelpers.CreateExport<IShowRuleInBrowser>(),
MefTestHelpers.CreateExport<IRuleHelpXamlBuilder>(),
MefTestHelpers.CreateExport<ILogger>());

[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<RuleHelpToolWindow, IRuleHelpToolWindow>().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<Guid?>());

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<Education, IEducation>(
MefTestHelpers.CreateExport<IToolWindowService>(),
MefTestHelpers.CreateExport<IRuleMetaDataProvider>(),
MefTestHelpers.CreateExport<IShowRuleInBrowser>(),
MefTestHelpers.CreateExport<IRuleHelpXamlBuilder>(),
MefTestHelpers.CreateExport<ILogger>());
}
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<Guid?>()).Returns(ruleInfo);

[TestMethod]
public void ShowRuleHelp_KnownRule_DocumentIsDisplayedInToolWindow()
{
var ruleMetaDataProvider = new Mock<IRuleMetaDataProvider>();
var ruleId = new SonarCompositeRuleId("repoKey", "ruleKey");

var ruleInfo = Mock.Of<IRuleInfo>();
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 by SLVS-1630 */ null)).Returns(flowDocument);

var ruleDescriptionToolWindow = new Mock<IRuleHelpToolWindow>();

var toolWindowService = new Mock<IToolWindowService>();
toolWindowService.Setup(x => x.GetToolWindow<RuleHelpToolWindow, IRuleHelpToolWindow>()).Returns(ruleDescriptionToolWindow.Object);

var showRuleInBrowser = new Mock<IShowRuleInBrowser>();
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<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);

showRuleInBrowser.Invocations.Should().HaveCount(0);
}

[TestMethod]
public void ShowRuleHelp_FailedToDisplayRule_RuleIsShownInBrowser()
{
var toolWindowService = new Mock<IToolWindowService>();
var ruleMetadataProvider = new Mock<IRuleMetaDataProvider>();
var ruleHelpXamlBuilder = new Mock<IRuleHelpXamlBuilder>();
var showRuleInBrowser = new Mock<IShowRuleInBrowser>();

var ruleId = new SonarCompositeRuleId("repoKey", "ruleKey");

var ruleInfo = Mock.Of<IRuleInfo>();
ruleMetadataProvider.Setup(x => x.GetRuleInfoAsync(It.IsAny<SonarCompositeRuleId>(), It.IsAny<Guid?>())).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<Guid?>()), 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<IToolWindowService>();
var ruleMetadataProvider = new Mock<IRuleMetaDataProvider>();
var ruleHelpXamlBuilder = new Mock<IRuleHelpXamlBuilder>();
var showRuleInBrowser = new Mock<IShowRuleInBrowser>();

var unknownRule = new SonarCompositeRuleId("known", "xxx");
ruleMetadataProvider.Setup(x => x.GetRuleInfoAsync(unknownRule, It.IsAny<Guid?>())).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<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,
IRuleHelpXamlBuilder ruleHelpXamlBuilder = null)
{
toolWindowService ??= Mock.Of<IToolWindowService>();
ruleMetadataProvider ??= Mock.Of<IRuleMetaDataProvider>();
showRuleInBrowser ??= Mock.Of<IShowRuleInBrowser>();
ruleHelpXamlBuilder ??= Mock.Of<IRuleHelpXamlBuilder>();
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<Guid?>()).ReturnsNull();

private FlowDocument MockFlowDocument()
{
var flowDocument = Substitute.For<FlowDocument>();
ruleHelpXamlBuilder.Create(ruleInfo, /* todo by SLVS-1630 */ null).Returns(flowDocument);
return flowDocument;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<SonarErrorListEventProcessorProvider, ITableControlEventProcessorProvider>(
MefTestHelpers.CreateExport<IEducation>(),
MefTestHelpers.CreateExport<IErrorListHelper>(),
MefTestHelpers.CreateExport<ILogger>());
}
[TestMethod]
public void MefCtor_CheckIsExported() =>
MefTestHelpers.CheckTypeCanBeImported<SonarErrorListEventProcessorProvider, ITableControlEventProcessorProvider>(
MefTestHelpers.CreateExport<IEducation>(),
MefTestHelpers.CreateExport<IErrorListHelper>(),
MefTestHelpers.CreateExport<ILogger>());

[TestMethod]
public void Get_CreatesAndReturnsProcessor()
{
var testSubject = new SonarErrorListEventProcessorProvider(Mock.Of<IEducation>(), Mock.Of<IErrorListHelper>(), Mock.Of<ILogger>());
[TestMethod]
public void Get_CreatesAndReturnsProcessor()
{
var testSubject = new SonarErrorListEventProcessorProvider(Substitute.For<IEducation>(), Substitute.For<IErrorListHelper>(), Substitute.For<ILogger>());

var actual = testSubject.GetAssociatedEventProcessor(Mock.Of<IWpfTableControl>());
var actual = testSubject.GetAssociatedEventProcessor(Substitute.For<IWpfTableControl>());

actual.Should().NotBeNull();
}
actual.Should().NotBeNull();
}
}
Loading

0 comments on commit 9ba426c

Please sign in to comment.