diff --git a/src/Integration.Vsix.UnitTests/CFamily/VcxProject/FileConfigProviderTests.cs b/src/Integration.Vsix.UnitTests/CFamily/VcxProject/FileConfigProviderTests.cs index 59f40aff0..38d25e8b8 100644 --- a/src/Integration.Vsix.UnitTests/CFamily/VcxProject/FileConfigProviderTests.cs +++ b/src/Integration.Vsix.UnitTests/CFamily/VcxProject/FileConfigProviderTests.cs @@ -29,6 +29,7 @@ using SonarLint.VisualStudio.Integration.Vsix.CFamily.VcxProject; using static SonarLint.VisualStudio.Integration.Vsix.CFamily.UnitTests.CFamilyTestUtility; using System.IO.Abstractions; +using SonarLint.VisualStudio.Core.SystemAbstractions; namespace SonarLint.VisualStudio.Integration.UnitTests.CFamily.VcxProject { @@ -43,18 +44,19 @@ public class FileConfigProviderTests private FileConfigProvider testSubject; private const string ClFilePath = "C:\\path\\cl.exe"; - private static Mock CreateFileSystemWithExistingFile(string fullPath) + private static IFileSystemService CreateFileSystemWithExistingFile(string fullPath) { - var fileSystem = new Mock(); - fileSystem.Setup(x => x.File.Exists(fullPath)).Returns(true); + var fileSystem = Substitute.For(); + fileSystem.File.Exists(fullPath).Returns(true); return fileSystem; } - private static Mock CreateFileSystemWithClCompiler() => CreateFileSystemWithExistingFile(ClFilePath); + private static IFileSystemService CreateFileSystemWithClCompiler() => CreateFileSystemWithExistingFile(ClFilePath); [TestMethod] public void MefCtor_CheckIsExported() => MefTestHelpers.CheckTypeCanBeImported( MefTestHelpers.CreateExport(), + MefTestHelpers.CreateExport(), MefTestHelpers.CreateExport(), MefTestHelpers.CreateExport(), MefTestHelpers.CreateExport()); @@ -70,10 +72,7 @@ public void TestInitialize() dte = Substitute.For(); uiServiceOperation = CreateDefaultUiServiceOperation(dte); - testSubject = new FileConfigProvider(uiServiceOperation, fileInSolutionIndicator, logger, new NoOpThreadHandler()) - { - FileSystem = CreateFileSystemWithClCompiler().Object - }; + testSubject = new FileConfigProvider(uiServiceOperation, fileInSolutionIndicator, CreateFileSystemWithClCompiler(), logger, new NoOpThreadHandler()); } private static IFileInSolutionIndicator CreateDefaultFileInSolutionIndicator() diff --git a/src/Integration.Vsix/CFamily/VcxProject/FileConfig.cs b/src/Integration.Vsix/CFamily/VcxProject/FileConfig.cs index 1c1815318..5fad5ca9f 100644 --- a/src/Integration.Vsix/CFamily/VcxProject/FileConfig.cs +++ b/src/Integration.Vsix/CFamily/VcxProject/FileConfig.cs @@ -29,46 +29,47 @@ namespace SonarLint.VisualStudio.Integration.Vsix.CFamily.VcxProject { internal class FileConfig : IFileConfig { - private static string GetCompilerPathFromClCompilerPath(ILogger logger, VCConfiguration vcConfig, IFileSystem fileSystem) + private static bool TryGetCompilerPathFromClCompilerPath(ILogger logger, VCConfiguration vcConfig, IFileSystem fileSystem, out string compilerPath) { - var compilerPath = vcConfig.GetEvaluatedPropertyValue("ClCompilerPath"); + compilerPath = vcConfig.GetEvaluatedPropertyValue("ClCompilerPath"); if (string.IsNullOrEmpty(compilerPath)) { logger.WriteLine("\"ClCompilerPath\" was not found."); - return null; + return false; } if (!fileSystem.File.Exists(compilerPath)) { logger.WriteLine($"Compiler path \"{compilerPath}\" does not exist."); - return null; + return false; } - return compilerPath; + return true; } - private static string GetCompilerPathFromExecutablePath(ILogger logger, VCConfiguration vcConfig, IFileSystem fileSystem) + private static bool TryGetCompilerPathFromExecutablePath(ILogger logger, VCConfiguration vcConfig, IFileSystem fileSystem, out string compilerPath) { + compilerPath = default; var executablePath = vcConfig.GetEvaluatedPropertyValue("ExecutablePath"); if (string.IsNullOrEmpty(executablePath)) { logger.WriteLine("\"ExecutablePath\" was not found."); - return null; + return false; } var toolExe = vcConfig.GetEvaluatedPropertyValue("CLToolExe"); if (string.IsNullOrEmpty(toolExe)) { logger.WriteLine("\"CLToolExe\" was not found."); - return null; + return false; } foreach (var path in executablePath.Split(';')) { - var compilerPath = Path.Combine(path, toolExe); + compilerPath = Path.Combine(path, toolExe); if (fileSystem.File.Exists(compilerPath)) { - return compilerPath; + return true; } else { @@ -76,50 +77,47 @@ private static string GetCompilerPathFromExecutablePath(ILogger logger, VCConfig } } - return null; + return false; } - private static string GetCompilerPathFromVCExecutablePath(ILogger logger, VCConfiguration vcConfig, IFileSystem fileSystem) + private static bool TryGetCompilerPathFromVCExecutablePath(ILogger logger, VCConfiguration vcConfig, IFileSystem fileSystem, out string compilerPath) { var platform = ((VCPlatform)vcConfig.Platform).Name.Contains("64") ? "x64" : "x86"; var exeVar = "VC_ExecutablePath_" + platform; - var compilerPath = Path.Combine(vcConfig.GetEvaluatedPropertyValue(exeVar), "cl.exe"); + compilerPath = Path.Combine(vcConfig.GetEvaluatedPropertyValue(exeVar), "cl.exe"); if (fileSystem.File.Exists(compilerPath)) { - return compilerPath; + return true; } else { logger.WriteLine($"Compiler path \"{compilerPath}\" does not exist."); - return null; + return false; } } - private static string GetCompilerPath(ILogger logger, VCConfiguration vcConfig, IFileSystem fileSystem) + private static bool GetCompilerPath(ILogger logger, VCConfiguration vcConfig, IFileSystem fileSystem, out string compilerPath) { - var compilerPath = GetCompilerPathFromClCompilerPath(logger, vcConfig, fileSystem); - if (!string.IsNullOrEmpty(compilerPath)) + if (TryGetCompilerPathFromClCompilerPath(logger, vcConfig, fileSystem, out compilerPath)) { - return compilerPath; + return true; } // Fallback to ExecutablePath and CLToolExe - compilerPath = GetCompilerPathFromExecutablePath(logger, vcConfig, fileSystem); - if (!string.IsNullOrEmpty(compilerPath)) + if (TryGetCompilerPathFromExecutablePath(logger, vcConfig, fileSystem, out compilerPath)) { - return compilerPath; + return true; } // Fallback to VC_ExecutablePath, which is used to be used in VS2017 toolchains // because ClCompilerPath was not available - compilerPath = GetCompilerPathFromVCExecutablePath(logger, vcConfig, fileSystem); - if (!string.IsNullOrEmpty(compilerPath)) + if (TryGetCompilerPathFromVCExecutablePath(logger, vcConfig, fileSystem, out compilerPath)) { - return compilerPath; + return true; } logger.WriteLine("Compiler is not supported."); - return null; + return false; } [ExcludeFromCodeCoverage] @@ -143,8 +141,7 @@ public static FileConfig TryGet(ILogger logger, ProjectItem dteProjectItem, stri bool isHeaderFile = vcFile.ItemType == "ClInclude"; CmdBuilder cmdBuilder = new CmdBuilder(isHeaderFile); - var compilerPath = GetCompilerPath(logger, vcConfig, fileSystem); - if (string.IsNullOrEmpty(compilerPath)) + if (!GetCompilerPath(logger, vcConfig, fileSystem, out var compilerPath)) { return null; } diff --git a/src/Integration.Vsix/CFamily/VcxProject/FileConfigProvider.cs b/src/Integration.Vsix/CFamily/VcxProject/FileConfigProvider.cs index 07b21af5b..cc62dca69 100644 --- a/src/Integration.Vsix/CFamily/VcxProject/FileConfigProvider.cs +++ b/src/Integration.Vsix/CFamily/VcxProject/FileConfigProvider.cs @@ -28,6 +28,7 @@ using SonarLint.VisualStudio.Infrastructure.VS; using SonarLint.VisualStudio.Integration.Helpers; using System.IO.Abstractions; +using SonarLint.VisualStudio.Core.SystemAbstractions; namespace SonarLint.VisualStudio.Integration.Vsix.CFamily.VcxProject { @@ -42,11 +43,11 @@ internal interface IFileConfigProvider internal class FileConfigProvider( IVsUIServiceOperation uiServiceOperation, IFileInSolutionIndicator fileInSolutionIndicator, + IFileSystemService fileSystem, ILogger logger, IThreadHandling threadHandling) : IFileConfigProvider { private static readonly NoOpLogger noOpLogger = new NoOpLogger(); - public IFileSystem FileSystem { get; set; } = new FileSystem(); public IFileConfig Get(string analyzedFilePath, CFamilyAnalyzerOptions analyzerOptions) { @@ -77,7 +78,7 @@ private FileConfig GetInternal(string analyzedFilePath, DTE2 dte, ILogger analys // Note: if the C++ tools are not installed then it's likely an exception will be thrown when // the framework tries to JIT-compile the TryGet method (since it won't be able to find the MS.VS.VCProjectEngine // types). - return FileConfig.TryGet(analysisLogger, projectItem, analyzedFilePath, FileSystem); + return FileConfig.TryGet(analysisLogger, projectItem, analyzedFilePath, fileSystem); } catch (Exception ex) when (!Microsoft.VisualStudio.ErrorHandler.IsCriticalException(ex)) {