Skip to content

Commit

Permalink
[Infra] Add helper class to encapsulate using a VS service (#4860)
Browse files Browse the repository at this point in the history
* [Infra] Add helper class to encapsulate using a VS service

Fixes #4859
  • Loading branch information
duncanp-sonar authored and ugras-ergun-sonarsource committed Oct 9, 2023
1 parent 39d0d13 commit 081ae38
Show file tree
Hide file tree
Showing 4 changed files with 520 additions and 19 deletions.
49 changes: 37 additions & 12 deletions src/Infrastructure.VS.UnitTests/VsInfoServiceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
using System.Runtime.InteropServices;
using FluentAssertions;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
Expand All @@ -34,18 +33,32 @@ namespace SonarLint.VisualStudio.Infrastructure.VS.UnitTests
public class VsInfoServiceTests
{
[TestMethod]
public void MefCtor_CheckIsExported()
public void MefCtor_CheckIsExported()
=> MefTestHelpers.CheckTypeCanBeImported<VsInfoService, IVsInfoService>(
MefTestHelpers.CreateExport<IVsUIServiceOperation>());

[TestMethod]
public void MefCtor_CheckIsSingleton()
=> MefTestHelpers.CheckIsSingletonMefComponent<VsInfoService>();

[TestMethod]
public void MefCtor_DoesNotCallAnyServices()
{
MefTestHelpers.CheckTypeCanBeImported<VsInfoService, IVsInfoService>(
MefTestHelpers.CreateExport<SVsServiceProvider>(CreateConfiguredServiceProvider("anypath").Object));
var serviceOp = new Mock<IVsUIServiceOperation>();

_ = new VsInfoService(serviceOp.Object);

// 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 Create_VsShellCallSucceeds_ReturnsExpectedPath()
{
var serviceProvider = CreateConfiguredServiceProvider("c:\\test\\");
var serviceOp = CreateConfiguredServiceOperation("c:\\test\\");

var testSubject = new VsInfoService(serviceProvider.Object);
var testSubject = new VsInfoService(serviceOp);

testSubject.InstallRootDir.Should().Be("c:\\test\\");
}
Expand All @@ -54,22 +67,34 @@ public void Create_VsShellCallSucceeds_ReturnsExpectedPath()
public void Create_VsShellCallFails_ExceptionThrown()
{
var logger = new TestLogger();
var serviceProvider = CreateConfiguredServiceProvider("c:\\test\\", shellHrResult: -123);
var serviceOp = CreateConfiguredServiceOperation("c:\\test\\", shellHrResult: -123);

Action act = () => new VsInfoService(serviceProvider.Object);
var testSubject = new VsInfoService(serviceOp);

Action act = () => _ = testSubject.InstallRootDir;
act.Should().ThrowExactly<COMException>();
}

private Mock<IServiceProvider> CreateConfiguredServiceProvider(string installDirectory, int shellHrResult = VSConstants.S_OK)
private IVsUIServiceOperation CreateConfiguredServiceOperation(string installDirectory, int shellHrResult = VSConstants.S_OK)
{
object installDir = installDirectory;
var vsShell = new Mock<IVsShell>();
vsShell.Setup(x => x.GetProperty((int)__VSSPROPID2.VSSPROPID_InstallRootDir, out installDir)).Returns(shellHrResult);

var serviceProvider = new Mock<IServiceProvider>();
serviceProvider.Setup(x => x.GetService(typeof(SVsShell))).Returns(vsShell.Object);
var serviceOp = CreateServiceOperation(vsShell.Object);

return serviceOp;
}

private IVsUIServiceOperation CreateServiceOperation(IVsShell svcToPassToCallback)
{
var serviceOp = new Mock<IVsUIServiceOperation>();

// Set up the mock to invoke the operation with the supplied VS service
serviceOp.Setup(x => x.Execute<SVsShell, IVsShell, string>(It.IsAny<Func<IVsShell, string>>()))
.Returns<Func<IVsShell, string>>(op => op(svcToPassToCallback));

return serviceProvider;
return serviceOp.Object;
}
}
}
Loading

0 comments on commit 081ae38

Please sign in to comment.