From 3a20f5b3018f11be29b6fb36e799c6159a05f3d1 Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Tue, 31 Oct 2023 13:42:31 +0100 Subject: [PATCH 01/35] Add Nuget --- .../BinaryToXmlCoverageReportConverter.cs | 44 +++++-------------- .../SonarScanner.MSBuild.TFS.Classic.csproj | 1 + 2 files changed, 13 insertions(+), 32 deletions(-) diff --git a/src/SonarScanner.MSBuild.TFS.Classic/BinaryToXmlCoverageReportConverter.cs b/src/SonarScanner.MSBuild.TFS.Classic/BinaryToXmlCoverageReportConverter.cs index f61fc8402..8c5d21c6f 100644 --- a/src/SonarScanner.MSBuild.TFS.Classic/BinaryToXmlCoverageReportConverter.cs +++ b/src/SonarScanner.MSBuild.TFS.Classic/BinaryToXmlCoverageReportConverter.cs @@ -25,6 +25,7 @@ using System.IO; using System.Linq; using System.Text.RegularExpressions; +using Microsoft.CodeCoverage.IO; using Microsoft.VisualStudio.Setup.Configuration; using Microsoft.Win32; using SonarScanner.MSBuild.Common; @@ -333,38 +334,17 @@ public static bool ConvertBinaryToXml(string converterExeFilePath, string inputB Debug.Assert(File.Exists(inputBinaryFilePath), "Expecting the input file to exist: " + inputBinaryFilePath); Debug.Assert(Path.IsPathRooted(outputXmlFilePath), "Expecting the output file name to be a full absolute path"); - var args = new List - { - "analyze", - string.Format(CultureInfo.InvariantCulture, @"/output:{0}", outputXmlFilePath), - inputBinaryFilePath - }; - - var scannerArgs = new ProcessRunnerArguments(converterExeFilePath, false) - { - WorkingDirectory = Path.GetDirectoryName(outputXmlFilePath), - CmdLineArgs = args, - TimeoutInMilliseconds = ConversionTimeoutInMs - }; - - var runner = new ProcessRunner(logger); - var success = runner.Execute(scannerArgs); - - if (success) - { - // Check the output file actually exists - if (!File.Exists(outputXmlFilePath)) - { - logger.LogError(Resources.CONV_ERROR_OutputFileNotFound, outputXmlFilePath); - success = false; - } - } - else - { - logger.LogError(Resources.CONV_ERROR_ConversionToolFailed, inputBinaryFilePath); - } - - return success; + // TODO: try/catch + // TODO: Logging + // TODO: What are the right values for includeSkippedFunctions and includeSkippedModules + var util = new CoverageFileUtility(); + util.ConvertCoverageFile( + path: inputBinaryFilePath, + outputPath: outputXmlFilePath, + includeSkippedFunctions: true, + includeSkippedModules: true); + + return true; } #endregion Private methods diff --git a/src/SonarScanner.MSBuild.TFS.Classic/SonarScanner.MSBuild.TFS.Classic.csproj b/src/SonarScanner.MSBuild.TFS.Classic/SonarScanner.MSBuild.TFS.Classic.csproj index db212169e..f3fe799f2 100644 --- a/src/SonarScanner.MSBuild.TFS.Classic/SonarScanner.MSBuild.TFS.Classic.csproj +++ b/src/SonarScanner.MSBuild.TFS.Classic/SonarScanner.MSBuild.TFS.Classic.csproj @@ -40,6 +40,7 @@ + From 1269fbe22aa724e98d12c5a8a0406b1f83b4f84e Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Tue, 31 Oct 2023 14:14:07 +0100 Subject: [PATCH 02/35] WIP: Remove usused dependencies from BinaryToXmlCoverageReportConverter --- ...BinaryToXmlCoverageReportConverterTests.cs | 8 +- .../BinaryToXmlCoverageReportConverter.cs | 270 +----------------- .../Resources.Designer.cs | 99 ------- .../Resources.resx | 34 --- 4 files changed, 7 insertions(+), 404 deletions(-) diff --git a/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs b/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs index a29acfb74..da700444b 100644 --- a/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs +++ b/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs @@ -90,7 +90,7 @@ echo Error output...>&2 echo foo > """ + outputFilePath + @""""); // Act - var success = BinaryToXmlCoverageReportConverter.ConvertBinaryToXml(converterFilePath, inputFilePath, outputFilePath, logger); + var success = BinaryToXmlCoverageReportConverter.ConvertBinaryToXml(inputFilePath, outputFilePath, logger); // Assert success.Should().BeTrue("Expecting the process to succeed"); @@ -119,7 +119,7 @@ public void Conv_FailsIfFileNotFound() File.WriteAllText(converterFilePath, @"REM Do nothing - don't create a file"); // Act - var success = BinaryToXmlCoverageReportConverter.ConvertBinaryToXml(converterFilePath, inputFilePath, outputFilePath, logger); + var success = BinaryToXmlCoverageReportConverter.ConvertBinaryToXml(inputFilePath, outputFilePath, logger); // Assert success.Should().BeFalse("Expecting the process to fail"); @@ -146,7 +146,7 @@ public void Conv_FailsIfFileConverterReturnsAnErrorCode() File.WriteAllText(converterFilePath, @"exit -1"); // Act - var success = BinaryToXmlCoverageReportConverter.ConvertBinaryToXml(converterFilePath, inputFilePath, outputFilePath, logger); + var success = BinaryToXmlCoverageReportConverter.ConvertBinaryToXml(inputFilePath, outputFilePath, logger); // Assert success.Should().BeFalse("Expecting the process to fail"); @@ -178,7 +178,7 @@ echo Converter called with %argC% args echo success > """ + outputFilePath + @""""); // Act - var success = BinaryToXmlCoverageReportConverter.ConvertBinaryToXml(converterFilePath, inputFilePath, outputFilePath, logger); + var success = BinaryToXmlCoverageReportConverter.ConvertBinaryToXml(inputFilePath, outputFilePath, logger); // Assert success.Should().BeTrue("Expecting the process to succeed"); diff --git a/src/SonarScanner.MSBuild.TFS.Classic/BinaryToXmlCoverageReportConverter.cs b/src/SonarScanner.MSBuild.TFS.Classic/BinaryToXmlCoverageReportConverter.cs index 8c5d21c6f..f42aae75e 100644 --- a/src/SonarScanner.MSBuild.TFS.Classic/BinaryToXmlCoverageReportConverter.cs +++ b/src/SonarScanner.MSBuild.TFS.Classic/BinaryToXmlCoverageReportConverter.cs @@ -19,53 +19,16 @@ */ using System; -using System.Collections.Generic; using System.Diagnostics; -using System.Globalization; using System.IO; -using System.Linq; -using System.Text.RegularExpressions; using Microsoft.CodeCoverage.IO; -using Microsoft.VisualStudio.Setup.Configuration; -using Microsoft.Win32; using SonarScanner.MSBuild.Common; namespace SonarScanner.MSBuild.TFS.Classic { public class BinaryToXmlCoverageReportConverter : ICoverageReportConverter { - private const int ConversionTimeoutInMs = 60000; - private readonly IVisualStudioSetupConfigurationFactory setupConfigurationFactory; private readonly ILogger logger; - private readonly AnalysisConfig config; - - /// - /// Registry containing information about installed VS versions - /// - private const string VisualStudioRegistryPath_32Bit = @"SOFTWARE\Microsoft\VisualStudio"; - private const string VisualStudioRegistryPath_64Bit = @"SOFTWARE\Wow6432Node\Microsoft\VisualStudio"; - - /// - /// Partial path to the code coverage exe, from the Visual Studio shell folder - /// - private const string TeamToolFullPath = @"Team Tools\Dynamic Code Coverage Tools\CodeCoverage.exe"; - - private static readonly string[] VsTestToolPlatformInstallerPathToExe = - { - @"tools\net451\Team Tools\Dynamic Code Coverage Tools\CodeCoverage.exe", // version https://www.nuget.org/packages/Microsoft.TestPlatform/17.3.2 and below - @"tools\net462\Team Tools\Dynamic Code Coverage Tools\CodeCoverage.exe" // version https://www.nuget.org/packages/Microsoft.TestPlatform/17.4.0 and above - }; - - /// - /// Code coverage package names for Visual Studio setup configuration - /// - private static readonly string[] CodeCoverageInstallationPackageNames = - { - "Microsoft.VisualStudio.TestTools.CodeCoverage", - "Microsoft.VisualStudio.TestTools.CodeCoverage.Msi" - }; - - private string conversionToolPath; #region Public methods @@ -76,33 +39,14 @@ public BinaryToXmlCoverageReportConverter(ILogger logger, AnalysisConfig config) public BinaryToXmlCoverageReportConverter(IVisualStudioSetupConfigurationFactory setupConfigurationFactory, ILogger logger, AnalysisConfig config) { - this.setupConfigurationFactory = setupConfigurationFactory; this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); - this.config = config ?? throw new ArgumentNullException(nameof(config)); } #endregion Public methods #region IReportConverter interface - public bool Initialize() - { - bool success; - - conversionToolPath = GetExeToolPath(); - - if (conversionToolPath == null) - { - logger.LogWarning(Resources.CONV_WARN_FailToFindConversionTool); - success = false; - } - else - { - logger.LogDebug(Resources.CONV_DIAG_CommandLineToolInfo, conversionToolPath); - success = true; - } - return success; - } + public bool Initialize() => true; public bool ConvertToXml(string inputFilePath, string outputFilePath) { @@ -115,221 +59,15 @@ public bool ConvertToXml(string inputFilePath, string outputFilePath) throw new ArgumentNullException(nameof(outputFilePath)); } - return ConvertBinaryToXml(conversionToolPath, inputFilePath, outputFilePath, logger); + return ConvertBinaryToXml(inputFilePath, outputFilePath, logger); } #endregion IReportConverter interface - #region Private methods - - private string GetExeToolPath() - { - logger.LogDebug(Resources.CONV_DIAG_LocatingCodeCoverageTool); - - var userSuppliedVsCoverageToolPath = config.GetVsCoverageConverterToolPath(); - if (!string.IsNullOrEmpty(userSuppliedVsCoverageToolPath)) - { - logger.LogDebug(Resources.CONV_DIAG_LocatingCodeCoverageToolUserSuppliedProperty); - if (userSuppliedVsCoverageToolPath.EndsWith("CodeCoverage.exe") && File.Exists(userSuppliedVsCoverageToolPath)) - { - logger.LogDebug(Resources.CONV_DIAG_CodeCoverageFound, userSuppliedVsCoverageToolPath); - return userSuppliedVsCoverageToolPath; - } - - foreach (var subPath in VsTestToolPlatformInstallerPathToExe) - { - var standardToolInstallerPath = Path.Combine(userSuppliedVsCoverageToolPath, subPath); - logger.LogDebug(Resources.CONV_DIAG_CodeCoverageIsNotInVariable, userSuppliedVsCoverageToolPath, subPath); - if (File.Exists(standardToolInstallerPath)) - { - logger.LogDebug(Resources.CONV_DIAG_CodeCoverageFound, standardToolInstallerPath); - return standardToolInstallerPath; - } - } - logger.LogWarning(Resources.CONV_WARN_UnableToFindCodeCoverageFileInUserSuppliedVariable); - } - - return GetExeToolPathFromSetupConfiguration() - ?? GetExeToolPathFromRegistry(); - } - - #region Code Coverage Tool path from setup configuration - - private string GetExeToolPathFromSetupConfiguration() - { - string toolPath = null; - - logger.LogDebug(Resources.CONV_DIAG_LocatingCodeCoverageToolSetupConfiguration); - var configurationQuery = setupConfigurationFactory.GetSetupConfigurationQuery(); - if (configurationQuery != null) - { - var instanceEnumerator = configurationQuery.EnumInstances(); - - int fetched; - var tempInstance = new ISetupInstance[1]; - - var instances = new List(); - //Enumerate the configuration instances - do - { - instanceEnumerator.Next(1, tempInstance, out fetched); - if (fetched > 0) - { - var instance = (ISetupInstance2)tempInstance[0]; - if (instance.GetPackages().Any(p => CodeCoverageInstallationPackageNames.Contains(p.GetId()))) - { - //Store instances that have code coverage package installed - instances.Add((ISetupInstance2)tempInstance[0]); - } - } - } while (fetched > 0); - - if (instances.Count > 1) - { - logger.LogDebug(Resources.CONV_DIAG_MultipleVsVersionsInstalled, string.Join(", ", instances.Select(i => - i.GetInstallationVersion()))); - } - - //Get the installation path for the latest visual studio found - var visualStudioPath = instances.OrderByDescending(i => i.GetInstallationVersion()) - .Select(i => i.GetInstallationPath()) - .FirstOrDefault(); - - if (visualStudioPath != null) - { - toolPath = Path.Combine(visualStudioPath, TeamToolFullPath); - } - } - else - { - logger.LogDebug(Resources.CONV_DIAG_SetupConfigurationNotSupported); - } - - return toolPath; - } - - #endregion Code Coverage Tool path from setup configuration - - #region Code Coverage Tool path from registry - - private string GetExeToolPathFromRegistry() - { - string toolPath = null; - - logger.LogDebug(Resources.CONV_DIAG_LocatingCodeCoverageToolRegistry); - - var regPath = GetVsRegistryPath(Environment.Is64BitProcess); - - using (var key = Registry.LocalMachine.OpenSubKey(regPath, false)) - { - // i.e. no VS installed - if (key == null) - { - return null; - } - - var keys = key.GetSubKeyNames(); - - // Find the ShellFolder paths for the installed VS versions - var versionFolderMap = GetVsShellFolders(key, keys); - - // Attempt to locate the code coverage tool for each installed version - var versionToolMap = GetCoverageToolsPaths(versionFolderMap); - Debug.Assert(!versionToolMap.Keys.Any(k => double.IsNaN(k)), "Version key should be a number"); - - if (versionToolMap.Count > 1) - { - logger.LogDebug(Resources.CONV_DIAG_MultipleVsVersionsInstalled, string.Join(", ", versionToolMap.Keys)); - } - - if (versionToolMap.Count > 0) - { - // Use the latest version of the tool - var maxVersion = versionToolMap.Keys.Max(); - toolPath = versionToolMap[maxVersion]; - } - } - - return toolPath; - } - - public static string GetVsRegistryPath(bool is64BitProcess) - { - // Bug #461: https://github.com/SonarSource/sonar-scanner-msbuild/issues/461 - // The registry path to return depends on whether the OS is 32- or 64-bit, and - // whether the calling process is 32- or 64-bit. - // VS is (currently) still a 32-bit process. In most cases we should just return - // the 32-bit registry path, and rely on registry redirection to re-direct the - // path to the Wow6432Node if necessary. - // However, if we are running under a 64-bit process registry redirection won't - // happen, so we need to supply the full path ourselves. - return is64BitProcess ? VisualStudioRegistryPath_64Bit : VisualStudioRegistryPath_32Bit; - } - - /// - /// Returns a mapping of VS version (as a string e.g. "12.0") to the install directory for that version - /// - private static IDictionary GetVsShellFolders(RegistryKey vsKey, string[] keys) - { - var versionFolderMap = new Dictionary(); - foreach (var key in keys) - { - // Check for the shell dir subkey - if (Regex.IsMatch(key, @"\d+.\d+", RegexOptions.None, RegexConstants.DefaultTimeout) && Registry.GetValue(vsKey.Name + "\\" + key, "ShellFolder", null) - is string shellFolder) - { - versionFolderMap[key] = shellFolder; - } - } - return versionFolderMap; - } - - /// - /// Returns a mapping of VS version (as a double) to the full path to the code coverage - /// tool for that version. - /// - /// VS versions that cannot be converted successfully to a double will be ignored. - /// The returned map will only have entries for VS version for which the code coverage tool could be found. - private static IDictionary GetCoverageToolsPaths(IDictionary versionFolderMap) - { - var versionPathMap = new Dictionary(); - foreach (var kvp in versionFolderMap) - { - var toolPath = Path.Combine(kvp.Value, TeamToolFullPath); - if (File.Exists(toolPath)) - { - var version = TryGetVersionAsDouble(kvp.Key); - - if (!double.IsNaN(version)) - { - versionPathMap[version] = toolPath; - } - } - } - return versionPathMap; - } - - /// - /// Attempts to convert the supplied version to a double. - /// Returns NaN if the value could not be converted - /// - private static double TryGetVersionAsDouble(string versionKey) - { - if (!double.TryParse(versionKey, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out double result)) - { - result = double.NaN; - } - return result; - } - - #endregion Code Coverage Tool path from registry - // was internal - public static bool ConvertBinaryToXml(string converterExeFilePath, string inputBinaryFilePath, string outputXmlFilePath, + public static bool ConvertBinaryToXml(string inputBinaryFilePath, string outputXmlFilePath, ILogger logger) { - Debug.Assert(!string.IsNullOrEmpty(converterExeFilePath), "Expecting the conversion tool path to have been set"); - Debug.Assert(File.Exists(converterExeFilePath), "Expecting the converter exe to exist: " + converterExeFilePath); Debug.Assert(Path.IsPathRooted(inputBinaryFilePath), "Expecting the input file name to be a full absolute path"); Debug.Assert(File.Exists(inputBinaryFilePath), "Expecting the input file to exist: " + inputBinaryFilePath); Debug.Assert(Path.IsPathRooted(outputXmlFilePath), "Expecting the output file name to be a full absolute path"); @@ -346,7 +84,5 @@ public static bool ConvertBinaryToXml(string converterExeFilePath, string inputB return true; } - - #endregion Private methods } } diff --git a/src/SonarScanner.MSBuild.TFS.Classic/Resources.Designer.cs b/src/SonarScanner.MSBuild.TFS.Classic/Resources.Designer.cs index fad590aec..7997e2e8f 100644 --- a/src/SonarScanner.MSBuild.TFS.Classic/Resources.Designer.cs +++ b/src/SonarScanner.MSBuild.TFS.Classic/Resources.Designer.cs @@ -60,87 +60,6 @@ internal Resources() { } } - /// - /// Looks up a localized string similar to CodeCoverage.exe found at {0}.. - /// - internal static string CONV_DIAG_CodeCoverageFound { - get { - return ResourceManager.GetString("CONV_DIAG_CodeCoverageFound", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to VsTestToolsInstallerInstalledToolLocation environment variable doesn't contain full path to CodeCoverage.exe tool, seeking in standard place set by VSTestPlatformToolInstaller: {0} and {1}. - /// - internal static string CONV_DIAG_CodeCoverageIsNotInVariable { - get { - return ResourceManager.GetString("CONV_DIAG_CodeCoverageIsNotInVariable", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Code coverage command line tool: {0}. - /// - internal static string CONV_DIAG_CommandLineToolInfo { - get { - return ResourceManager.GetString("CONV_DIAG_CommandLineToolInfo", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Attempting to locate the CodeCoverage.exe tool.... - /// - internal static string CONV_DIAG_LocatingCodeCoverageTool { - get { - return ResourceManager.GetString("CONV_DIAG_LocatingCodeCoverageTool", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Attempting to locate the CodeCoverage.exe tool using registry.... - /// - internal static string CONV_DIAG_LocatingCodeCoverageToolRegistry { - get { - return ResourceManager.GetString("CONV_DIAG_LocatingCodeCoverageToolRegistry", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Attempting to locate the CodeCoverage.exe tool using setup configuration.... - /// - internal static string CONV_DIAG_LocatingCodeCoverageToolSetupConfiguration { - get { - return ResourceManager.GetString("CONV_DIAG_LocatingCodeCoverageToolSetupConfiguration", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to VsTestToolsInstallerInstalledToolLocation environment variable detected, seeking for CodeCoverage.exe location.... - /// - internal static string CONV_DIAG_LocatingCodeCoverageToolUserSuppliedProperty { - get { - return ResourceManager.GetString("CONV_DIAG_LocatingCodeCoverageToolUserSuppliedProperty", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Multiple versions of VS are installed: {0}. - /// - internal static string CONV_DIAG_MultipleVsVersionsInstalled { - get { - return ResourceManager.GetString("CONV_DIAG_MultipleVsVersionsInstalled", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Visual Studio setup configuration was not found.. - /// - internal static string CONV_DIAG_SetupConfigurationNotSupported { - get { - return ResourceManager.GetString("CONV_DIAG_SetupConfigurationNotSupported", resourceCulture); - } - } - /// /// Looks up a localized string similar to Failed to convert the downloaded code coverage tool to XML. No code coverage information will be uploaded to SonarQube. ///Check that the downloaded code coverage file ({0}) is valid by opening it in Visual Studio. If it is not, check that the internet security settings on the build machine allow files to be downloaded from the Team Foundation Server machine.. @@ -160,24 +79,6 @@ internal static string CONV_ERROR_OutputFileNotFound { } } - /// - /// Looks up a localized string similar to Failed to find the code coverage command line tool. Possible cause: Visual Studio is not installed, or the installed version does not support code coverage.. - /// - internal static string CONV_WARN_FailToFindConversionTool { - get { - return ResourceManager.GetString("CONV_WARN_FailToFindConversionTool", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to CodeCoverage.exe was not found in the standard locations. Please provide the full path of the tool using the VsTestToolsInstallerInstalledToolLocation variable.. - /// - internal static string CONV_WARN_UnableToFindCodeCoverageFileInUserSuppliedVariable { - get { - return ResourceManager.GetString("CONV_WARN_UnableToFindCodeCoverageFileInUserSuppliedVariable", resourceCulture); - } - } - /// /// Looks up a localized string similar to Connected to {0}. /// diff --git a/src/SonarScanner.MSBuild.TFS.Classic/Resources.resx b/src/SonarScanner.MSBuild.TFS.Classic/Resources.resx index ce25b17d3..066674044 100644 --- a/src/SonarScanner.MSBuild.TFS.Classic/Resources.resx +++ b/src/SonarScanner.MSBuild.TFS.Classic/Resources.resx @@ -117,34 +117,6 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - CodeCoverage.exe found at {0}. - - - VsTestToolsInstallerInstalledToolLocation environment variable doesn't contain full path to CodeCoverage.exe tool, seeking in standard place set by VSTestPlatformToolInstaller: {0} and {1} - - - Code coverage command line tool: {0} - - - Attempting to locate the CodeCoverage.exe tool... - - - Attempting to locate the CodeCoverage.exe tool using registry... - - - Attempting to locate the CodeCoverage.exe tool using setup configuration... - - - VsTestToolsInstallerInstalledToolLocation environment variable detected, seeking for CodeCoverage.exe location... - - - Multiple versions of VS are installed: {0} - First parameter: a list of VS versions - - - Visual Studio setup configuration was not found. - Failed to convert the downloaded code coverage tool to XML. No code coverage information will be uploaded to SonarQube. Check that the downloaded code coverage file ({0}) is valid by opening it in Visual Studio. If it is not, check that the internet security settings on the build machine allow files to be downloaded from the Team Foundation Server machine. @@ -152,12 +124,6 @@ Check that the downloaded code coverage file ({0}) is valid by opening it in Vis Failed to convert the binary coverage file to XML. The expected output file was not found: {0} - - Failed to find the code coverage command line tool. Possible cause: Visual Studio is not installed, or the installed version does not support code coverage. - - - CodeCoverage.exe was not found in the standard locations. Please provide the full path of the tool using the VsTestToolsInstallerInstalledToolLocation variable. - Connected to {0} From 241ca9b5ee2f9199861856feef8a22abbfe6e995 Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Tue, 31 Oct 2023 14:20:57 +0100 Subject: [PATCH 03/35] Fix Conv_FailsIfFileConverterReturnsAnErrorCode --- ...BinaryToXmlCoverageReportConverterTests.cs | 3 --- .../BinaryToXmlCoverageReportConverter.cs | 19 ++++++++++++++----- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs b/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs index da700444b..0cf127c65 100644 --- a/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs +++ b/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs @@ -142,9 +142,6 @@ public void Conv_FailsIfFileConverterReturnsAnErrorCode() var inputFilePath = Path.Combine(testDir, "input.txt"); File.WriteAllText(inputFilePath, "dummy input file"); - var converterFilePath = Path.Combine(testDir, "converter.bat"); - File.WriteAllText(converterFilePath, @"exit -1"); - // Act var success = BinaryToXmlCoverageReportConverter.ConvertBinaryToXml(inputFilePath, outputFilePath, logger); diff --git a/src/SonarScanner.MSBuild.TFS.Classic/BinaryToXmlCoverageReportConverter.cs b/src/SonarScanner.MSBuild.TFS.Classic/BinaryToXmlCoverageReportConverter.cs index f42aae75e..166d558e7 100644 --- a/src/SonarScanner.MSBuild.TFS.Classic/BinaryToXmlCoverageReportConverter.cs +++ b/src/SonarScanner.MSBuild.TFS.Classic/BinaryToXmlCoverageReportConverter.cs @@ -22,6 +22,7 @@ using System.Diagnostics; using System.IO; using Microsoft.CodeCoverage.IO; +using Microsoft.CodeCoverage.IO.Exceptions; using SonarScanner.MSBuild.Common; namespace SonarScanner.MSBuild.TFS.Classic @@ -76,11 +77,19 @@ public static bool ConvertBinaryToXml(string inputBinaryFilePath, string outputX // TODO: Logging // TODO: What are the right values for includeSkippedFunctions and includeSkippedModules var util = new CoverageFileUtility(); - util.ConvertCoverageFile( - path: inputBinaryFilePath, - outputPath: outputXmlFilePath, - includeSkippedFunctions: true, - includeSkippedModules: true); + try + { + util.ConvertCoverageFile( + path: inputBinaryFilePath, + outputPath: outputXmlFilePath, + includeSkippedFunctions: true, + includeSkippedModules: true); + } + catch (AggregateException aggregate) when (aggregate.InnerException is InvalidCoverageFileException) + { + logger.LogError(Resources.CONV_ERROR_ConversionToolFailed, inputBinaryFilePath); + return false; + } return true; } From aaf00b99ef9c74c9666bdf0ee03d910f5a3fd69e Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Tue, 31 Oct 2023 14:22:50 +0100 Subject: [PATCH 04/35] Remove Conv_HasThreeArguments test --- ...BinaryToXmlCoverageReportConverterTests.cs | 30 ------------------- 1 file changed, 30 deletions(-) diff --git a/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs b/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs index 0cf127c65..bdc795215 100644 --- a/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs +++ b/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs @@ -153,36 +153,6 @@ public void Conv_FailsIfFileConverterReturnsAnErrorCode() File.Exists(outputFilePath).Should().BeFalse("Not expecting the output file to exist"); } - [TestMethod] - public void Conv_HasThreeArguments() - { - // Arrange - var logger = new TestLogger(); - var testDir = TestUtils.CreateTestSpecificFolderWithSubPaths(TestContext); - - var outputFilePath = Path.Combine(testDir, "output.txt"); - - var inputFilePath = Path.Combine(testDir, "input.txt"); - File.WriteAllText(inputFilePath, "dummy input file"); - - var converterFilePath = Path.Combine(testDir, "converter.bat"); - File.WriteAllText(converterFilePath, -@" -set argC=0 -for %%x in (%*) do Set /A argC+=1 - -echo Converter called with %argC% args -echo success > """ + outputFilePath + @""""); - - // Act - var success = BinaryToXmlCoverageReportConverter.ConvertBinaryToXml(inputFilePath, outputFilePath, logger); - - // Assert - success.Should().BeTrue("Expecting the process to succeed"); - - logger.AssertInfoLogged("Converter called with 3 args"); - } - [TestMethod] public void Initialize_CanGetGetExeToolPathFromSetupConfiguration() { From 5c021e204c50ec2698c26fd9dcefd7ad3b0f3232 Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Tue, 31 Oct 2023 14:23:31 +0100 Subject: [PATCH 05/35] Remove Initialize_CanGetGetExeToolPathFromSetupConfiguration test --- ...BinaryToXmlCoverageReportConverterTests.cs | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs b/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs index bdc795215..e93c09b9f 100644 --- a/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs +++ b/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs @@ -153,25 +153,6 @@ public void Conv_FailsIfFileConverterReturnsAnErrorCode() File.Exists(outputFilePath).Should().BeFalse("Not expecting the output file to exist"); } - [TestMethod] - public void Initialize_CanGetGetExeToolPathFromSetupConfiguration() - { - // Arrange - var logger = new TestLogger(); - - var factory = CreateVisualStudioSetupConfigurationFactory("Microsoft.VisualStudio.TestTools.CodeCoverage"); - - var reporter = new BinaryToXmlCoverageReportConverter(factory, logger, new AnalysisConfig()); - - // Act - var result = reporter.Initialize(); - - // Assert - result.Should().BeTrue(); - - logger.AssertDebugLogged("Code coverage command line tool: x:\\foo\\Team Tools\\Dynamic Code Coverage Tools\\CodeCoverage.exe"); - } - [TestMethod] public void Initialize_CanGetGetExeToolPathFromEnvironmentVariable_FullPathToCodeCoverageToolGiven() { From c1d6d1ae7bfe0ac550cc8c981ecf211cc17b793f Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Tue, 31 Oct 2023 14:23:54 +0100 Subject: [PATCH 06/35] Remove Initialize_CanGetGetExeToolPathFromEnvironmentVariable_FullPathToCodeCoverageToolGiven test --- ...BinaryToXmlCoverageReportConverterTests.cs | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs b/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs index e93c09b9f..5bee0a570 100644 --- a/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs +++ b/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs @@ -153,26 +153,6 @@ public void Conv_FailsIfFileConverterReturnsAnErrorCode() File.Exists(outputFilePath).Should().BeFalse("Not expecting the output file to exist"); } - [TestMethod] - public void Initialize_CanGetGetExeToolPathFromEnvironmentVariable_FullPathToCodeCoverageToolGiven() - { - // Arrange - var logger = new TestLogger(); - var config = new AnalysisConfig(); - var filePath = Path.Combine(Environment.CurrentDirectory, "CodeCoverage.exe"); - using var f = new TestFile(filePath); - config.SetVsCoverageConverterToolPath(filePath); - - var reporter = new BinaryToXmlCoverageReportConverter(logger, config); - - // Act - var result = reporter.Initialize(); - - // Assert - result.Should().BeTrue(); - - logger.AssertDebugLogged($@"CodeCoverage.exe found at {filePath}."); - } [TestMethod] public void Initialize_NoPath_ReturnsFalseAndLogsWarning() From 77f008078f56437d7d27b77219d8f6a4349b0654 Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Tue, 31 Oct 2023 14:24:27 +0100 Subject: [PATCH 07/35] Remove Initialize_NoPath_ReturnsFalseAndLogsWarning --- .../BinaryToXmlCoverageReportConverterTests.cs | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs b/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs index 5bee0a570..ae9fe4ede 100644 --- a/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs +++ b/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs @@ -153,19 +153,6 @@ public void Conv_FailsIfFileConverterReturnsAnErrorCode() File.Exists(outputFilePath).Should().BeFalse("Not expecting the output file to exist"); } - - [TestMethod] - public void Initialize_NoPath_ReturnsFalseAndLogsWarning() - { - var logger = new TestLogger(); - var reporter = new BinaryToXmlCoverageReportConverter(Mock.Of(), logger, new AnalysisConfig()); - - var result = reporter.Initialize(); - - result.Should().BeFalse(); - logger.AssertWarningLogged("Failed to find the code coverage command line tool. Possible cause: Visual Studio is not installed, or the installed version does not support code coverage."); - } - [DataTestMethod] [DoNotParallelize] [DataRow(@"tools\net451\Team Tools\Dynamic Code Coverage Tools\CodeCoverage.exe")] From ff710543a927e8536d04c417221d45613ed00774 Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Tue, 31 Oct 2023 14:24:48 +0100 Subject: [PATCH 08/35] Remove Initialize_CanGetGetExeToolPathFromEnvironmentVariable_NoExeInThePath_ShouldSeekForStandardInstall --- ...BinaryToXmlCoverageReportConverterTests.cs | 24 ------------------- 1 file changed, 24 deletions(-) diff --git a/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs b/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs index ae9fe4ede..1853baed0 100644 --- a/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs +++ b/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs @@ -153,30 +153,6 @@ public void Conv_FailsIfFileConverterReturnsAnErrorCode() File.Exists(outputFilePath).Should().BeFalse("Not expecting the output file to exist"); } - [DataTestMethod] - [DoNotParallelize] - [DataRow(@"tools\net451\Team Tools\Dynamic Code Coverage Tools\CodeCoverage.exe")] - [DataRow(@"tools\net462\Team Tools\Dynamic Code Coverage Tools\CodeCoverage.exe")] - public void Initialize_CanGetGetExeToolPathFromEnvironmentVariable_NoExeInThePath_ShouldSeekForStandardInstall(string standardPath) - { - // Arrange - var logger = new TestLogger(); - var config = new AnalysisConfig(); - - var filePath = Path.Combine(Environment.CurrentDirectory, standardPath); - Directory.CreateDirectory(Path.GetDirectoryName(filePath)); - using var f = new TestFile(filePath); - config.SetVsCoverageConverterToolPath(Environment.CurrentDirectory); - var reporter = new BinaryToXmlCoverageReportConverter(logger, config); - - // Act - var result = reporter.Initialize(); - - // Assert - result.Should().BeTrue(); - logger.AssertDebugLogged($@"CodeCoverage.exe found at {filePath}."); - } - [TestMethod] public void Initialize_CanGetGetExeToolPathFromEnvironmentVariable_FileDoesntExist_ShouldFallback() { From 503d77b009b3ad82924da7c4c9266ed662499e57 Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Tue, 31 Oct 2023 14:25:07 +0100 Subject: [PATCH 09/35] Remove Initialize_CanGetGetExeToolPathFromEnvironmentVariable_FileDoesntExist_ShouldFallback --- ...BinaryToXmlCoverageReportConverterTests.cs | 22 ------------------- 1 file changed, 22 deletions(-) diff --git a/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs b/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs index 1853baed0..3f91385d6 100644 --- a/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs +++ b/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs @@ -153,28 +153,6 @@ public void Conv_FailsIfFileConverterReturnsAnErrorCode() File.Exists(outputFilePath).Should().BeFalse("Not expecting the output file to exist"); } - [TestMethod] - public void Initialize_CanGetGetExeToolPathFromEnvironmentVariable_FileDoesntExist_ShouldFallback() - { - // Arrange - var logger = new TestLogger(); - var config = new AnalysisConfig(); - var factory = CreateVisualStudioSetupConfigurationFactory("Microsoft.VisualStudio.TestTools.CodeCoverage"); - - config.SetVsCoverageConverterToolPath(Path.GetTempPath()); - - var reporter = new BinaryToXmlCoverageReportConverter(factory, logger, config); - - // Act - var result = reporter.Initialize(); - - // Assert - result.Should().BeTrue(); - - logger.Warnings.Contains("CodeCoverage.exe was not found in the standard locations. Please provide the full path of the tool using the VsTestToolsInstallerInstalledToolLocation variable."); - logger.AssertDebugLogged("Code coverage command line tool: x:\\foo\\Team Tools\\Dynamic Code Coverage Tools\\CodeCoverage.exe"); - } - [TestMethod] public void Initialize_CanGetGetExeToolPathFromSetupConfigurationForBuildAgent() { From 9445ec54d772455ff404f001aa1aaa0c8ba6a80f Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Tue, 31 Oct 2023 15:37:26 +0100 Subject: [PATCH 10/35] Adopt Conv_OutputIsCaptured --- ...BinaryToXmlCoverageReportConverterTests.cs | 21 +++++-------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs b/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs index 3f91385d6..5b0fda61e 100644 --- a/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs +++ b/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs @@ -81,25 +81,17 @@ public void Conv_OutputIsCaptured() var inputFilePath = Path.Combine(testDir, "input.txt"); File.WriteAllText(inputFilePath, "dummy input file"); - var converterFilePath = Path.Combine(testDir, "converter.bat"); - File.WriteAllText(converterFilePath, -@" -echo Normal output... -echo Error output...>&2 -echo Create a new file using the output parameter -echo foo > """ + outputFilePath + @""""); - // Act var success = BinaryToXmlCoverageReportConverter.ConvertBinaryToXml(inputFilePath, outputFilePath, logger); // Assert - success.Should().BeTrue("Expecting the process to succeed"); + success.Should().BeFalse(); - File.Exists(outputFilePath).Should().BeTrue("Expecting the output file to exist"); - TestContext.AddResultFile(outputFilePath); + File.Exists(outputFilePath).Should().BeFalse("Conversion failed"); - logger.AssertInfoLogged("Normal output..."); - logger.AssertErrorLogged("Error output..."); + logger.AssertErrorLogged(@$"Failed to convert the downloaded code coverage tool to XML. No code coverage information will be uploaded to SonarQube. +Check that the downloaded code coverage file ({inputFilePath}) is valid by opening it in Visual Studio. If it is not, check that the internet security settings on the build machine allow files to be downloaded from the Team Foundation Server machine."); + logger.AssertNoWarningsLogged(); } [TestMethod] @@ -115,9 +107,6 @@ public void Conv_FailsIfFileNotFound() var inputFilePath = Path.Combine(testDir, "input.txt"); File.WriteAllText(inputFilePath, "dummy input file"); - var converterFilePath = Path.Combine(testDir, "converter.bat"); - File.WriteAllText(converterFilePath, @"REM Do nothing - don't create a file"); - // Act var success = BinaryToXmlCoverageReportConverter.ConvertBinaryToXml(inputFilePath, outputFilePath, logger); From 95439c7b447256828ad610e5f8239dca9ff7726e Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Tue, 31 Oct 2023 15:51:02 +0100 Subject: [PATCH 11/35] Remove Conv_FailsIfFileNotFound (duplicate of Conv_OutputIsCaptured) --- ...BinaryToXmlCoverageReportConverterTests.cs | 24 ------------------- 1 file changed, 24 deletions(-) diff --git a/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs b/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs index 5b0fda61e..62d730a65 100644 --- a/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs +++ b/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs @@ -94,30 +94,6 @@ public void Conv_OutputIsCaptured() logger.AssertNoWarningsLogged(); } - [TestMethod] - [WorkItem(72)] // Regression test for bug #72: fail the conversion if the output file is not created - public void Conv_FailsIfFileNotFound() - { - // Arrange - var logger = new TestLogger(); - var testDir = TestUtils.CreateTestSpecificFolderWithSubPaths(TestContext); - - var outputFilePath = Path.Combine(testDir, "output.txt"); - - var inputFilePath = Path.Combine(testDir, "input.txt"); - File.WriteAllText(inputFilePath, "dummy input file"); - - // Act - var success = BinaryToXmlCoverageReportConverter.ConvertBinaryToXml(inputFilePath, outputFilePath, logger); - - // Assert - success.Should().BeFalse("Expecting the process to fail"); - logger.AssertErrorsLogged(); - logger.AssertSingleErrorExists(outputFilePath); // error message should refer to the output file - - File.Exists(outputFilePath).Should().BeFalse("Not expecting the output file to exist"); - } - [TestMethod] [WorkItem(145)] // Regression test for bug #145: Poor UX if the code coverage report could not be converted to XML public void Conv_FailsIfFileConverterReturnsAnErrorCode() From 67c5f2007b260e1d1e39371b68e90fcb9f36320a Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Tue, 31 Oct 2023 15:52:10 +0100 Subject: [PATCH 12/35] Rename test --- .../Classic/BinaryToXmlCoverageReportConverterTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs b/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs index 62d730a65..85f5a1da1 100644 --- a/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs +++ b/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs @@ -70,7 +70,7 @@ public void Conv_ConvertToXml_InvalidArgs_Throws() [TestMethod] [WorkItem(72)] // Regression test for bug #72: CodeCoverage conversion - conversion errors should be detected and reported - public void Conv_OutputIsCaptured() + public void Conv_ConvertionFailure_Success_False_And_ErrorLogged() { // Arrange var logger = new TestLogger(); From e259aba2cc7fc35f3f531febf6c78a7d787668c6 Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Tue, 31 Oct 2023 16:08:09 +0100 Subject: [PATCH 13/35] Fix errors after re-base --- ...BinaryToXmlCoverageReportConverterTests.cs | 27 ------------------- 1 file changed, 27 deletions(-) diff --git a/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs b/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs index 85f5a1da1..52a7dfebc 100644 --- a/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs +++ b/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs @@ -118,33 +118,6 @@ public void Conv_FailsIfFileConverterReturnsAnErrorCode() File.Exists(outputFilePath).Should().BeFalse("Not expecting the output file to exist"); } - [TestMethod] - public void Initialize_CanGetGetExeToolPathFromSetupConfigurationForBuildAgent() - { - // Arrange - var logger = new TestLogger(); - - var factory = CreateVisualStudioSetupConfigurationFactory("Microsoft.VisualStudio.TestTools.CodeCoverage.Msi"); - - var reporter = new BinaryToXmlCoverageReportConverter(factory, logger, new AnalysisConfig()); - - // Act - var result = reporter.Initialize(); - - // Assert - result.Should().BeTrue(); - - logger.AssertDebugLogged("Code coverage command line tool: x:\\foo\\Team Tools\\Dynamic Code Coverage Tools\\CodeCoverage.exe"); - } - - [TestMethod] - public void GetRegistryPath_When64BitProcess_Returns64BitPath() => - BinaryToXmlCoverageReportConverter.GetVsRegistryPath(true).Should().Be(@"SOFTWARE\Wow6432Node\Microsoft\VisualStudio"); - - [TestMethod] - public void GetRegistryPath_When32BitProcess_Returns32BitPath() => - BinaryToXmlCoverageReportConverter.GetVsRegistryPath(false).Should().Be(@"SOFTWARE\Microsoft\VisualStudio"); - [CodeCoverageExeTestMethod] [DeploymentItem(@"Resources\Sample.coverage")] [DeploymentItem(@"Resources\Expected.xmlcoverage")] From 5678ef4de0f5ed55a16f19448cacd94e56e96286 Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Tue, 31 Oct 2023 16:29:21 +0100 Subject: [PATCH 14/35] Run Conv_ConvertToXml_ToolConvertsSampleFile in CI --- .../Classic/BinaryToXmlCoverageReportConverterTests.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs b/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs index 52a7dfebc..d87499aa4 100644 --- a/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs +++ b/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs @@ -118,7 +118,7 @@ public void Conv_FailsIfFileConverterReturnsAnErrorCode() File.Exists(outputFilePath).Should().BeFalse("Not expecting the output file to exist"); } - [CodeCoverageExeTestMethod] + [TestMethod] [DeploymentItem(@"Resources\Sample.coverage")] [DeploymentItem(@"Resources\Expected.xmlcoverage")] public void Conv_ConvertToXml_ToolConvertsSampleFile() @@ -126,9 +126,7 @@ public void Conv_ConvertToXml_ToolConvertsSampleFile() // Arrange var logger = new TestLogger(); var config = new AnalysisConfig(); - config.SetVsCoverageConverterToolPath(CodeCoverageExeTestMethodAttribute.FindCodeCoverageExe()); var reporter = new BinaryToXmlCoverageReportConverter(logger, config); - reporter.Initialize(); var inputFilePath = $"{Environment.CurrentDirectory}\\Sample.coverage"; var outputFilePath = $"{Environment.CurrentDirectory}\\Sample.xmlcoverage"; var expectedOutputFilePath = $"{Environment.CurrentDirectory}\\Expected.xmlcoverage"; From f0b43910c17b8883afeb6141d7749451b08d87cd Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Tue, 31 Oct 2023 17:01:31 +0100 Subject: [PATCH 15/35] Fix culture and checksum missmatches --- .../Resources/Expected.xmlcoverage | 2 +- .../ApplicationCultureInfo.cs | 27 +++++++++++++++++++ .../BinaryToXmlCoverageReportConverter.cs | 6 ++--- 3 files changed, 30 insertions(+), 5 deletions(-) create mode 100644 src/SonarScanner.MSBuild.Common/ApplicationCultureInfo.cs diff --git a/Tests/SonarScanner.MSBuild.TFS.Test/Resources/Expected.xmlcoverage b/Tests/SonarScanner.MSBuild.TFS.Test/Resources/Expected.xmlcoverage index b146d5f9a..039403b59 100644 --- a/Tests/SonarScanner.MSBuild.TFS.Test/Resources/Expected.xmlcoverage +++ b/Tests/SonarScanner.MSBuild.TFS.Test/Resources/Expected.xmlcoverage @@ -17,7 +17,7 @@ - + diff --git a/src/SonarScanner.MSBuild.Common/ApplicationCultureInfo.cs b/src/SonarScanner.MSBuild.Common/ApplicationCultureInfo.cs new file mode 100644 index 000000000..0166e6c24 --- /dev/null +++ b/src/SonarScanner.MSBuild.Common/ApplicationCultureInfo.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Text; + +namespace SonarScanner.MSBuild.Common +{ + public sealed class ApplicationCultureInfo : IDisposable + { + private readonly CultureInfo defaultThreadCurrentCulture; + private readonly CultureInfo defaultThreadCurrentUICulture; + + public ApplicationCultureInfo(CultureInfo setCultureInfo) + { + defaultThreadCurrentCulture = CultureInfo.DefaultThreadCurrentCulture; + defaultThreadCurrentUICulture = CultureInfo.DefaultThreadCurrentUICulture; + CultureInfo.DefaultThreadCurrentCulture = setCultureInfo; + CultureInfo.DefaultThreadCurrentUICulture = setCultureInfo; + } + + public void Dispose() + { + CultureInfo.DefaultThreadCurrentCulture = defaultThreadCurrentCulture; + CultureInfo.DefaultThreadCurrentUICulture = defaultThreadCurrentUICulture; + } + } +} diff --git a/src/SonarScanner.MSBuild.TFS.Classic/BinaryToXmlCoverageReportConverter.cs b/src/SonarScanner.MSBuild.TFS.Classic/BinaryToXmlCoverageReportConverter.cs index 166d558e7..cc7548653 100644 --- a/src/SonarScanner.MSBuild.TFS.Classic/BinaryToXmlCoverageReportConverter.cs +++ b/src/SonarScanner.MSBuild.TFS.Classic/BinaryToXmlCoverageReportConverter.cs @@ -20,6 +20,7 @@ using System; using System.Diagnostics; +using System.Globalization; using System.IO; using Microsoft.CodeCoverage.IO; using Microsoft.CodeCoverage.IO.Exceptions; @@ -73,12 +74,10 @@ public static bool ConvertBinaryToXml(string inputBinaryFilePath, string outputX Debug.Assert(File.Exists(inputBinaryFilePath), "Expecting the input file to exist: " + inputBinaryFilePath); Debug.Assert(Path.IsPathRooted(outputXmlFilePath), "Expecting the output file name to be a full absolute path"); - // TODO: try/catch - // TODO: Logging - // TODO: What are the right values for includeSkippedFunctions and includeSkippedModules var util = new CoverageFileUtility(); try { + using var dummy = new ApplicationCultureInfo(CultureInfo.InvariantCulture); util.ConvertCoverageFile( path: inputBinaryFilePath, outputPath: outputXmlFilePath, @@ -90,7 +89,6 @@ public static bool ConvertBinaryToXml(string inputBinaryFilePath, string outputX logger.LogError(Resources.CONV_ERROR_ConversionToolFailed, inputBinaryFilePath); return false; } - return true; } } From d35e94211eb08811fe1a34c3d8af145de6ad1d47 Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Tue, 31 Oct 2023 17:02:43 +0100 Subject: [PATCH 16/35] Turn off "includeSkipped" and fix checksum --- .../Resources/Expected.xmlcoverage | 2 +- .../BinaryToXmlCoverageReportConverter.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Tests/SonarScanner.MSBuild.TFS.Test/Resources/Expected.xmlcoverage b/Tests/SonarScanner.MSBuild.TFS.Test/Resources/Expected.xmlcoverage index 039403b59..db31fcff3 100644 --- a/Tests/SonarScanner.MSBuild.TFS.Test/Resources/Expected.xmlcoverage +++ b/Tests/SonarScanner.MSBuild.TFS.Test/Resources/Expected.xmlcoverage @@ -33,7 +33,7 @@ - + diff --git a/src/SonarScanner.MSBuild.TFS.Classic/BinaryToXmlCoverageReportConverter.cs b/src/SonarScanner.MSBuild.TFS.Classic/BinaryToXmlCoverageReportConverter.cs index cc7548653..d9e83d034 100644 --- a/src/SonarScanner.MSBuild.TFS.Classic/BinaryToXmlCoverageReportConverter.cs +++ b/src/SonarScanner.MSBuild.TFS.Classic/BinaryToXmlCoverageReportConverter.cs @@ -81,8 +81,8 @@ public static bool ConvertBinaryToXml(string inputBinaryFilePath, string outputX util.ConvertCoverageFile( path: inputBinaryFilePath, outputPath: outputXmlFilePath, - includeSkippedFunctions: true, - includeSkippedModules: true); + includeSkippedFunctions: false, + includeSkippedModules: false); } catch (AggregateException aggregate) when (aggregate.InnerException is InvalidCoverageFileException) { From 3ad7e9b69058b27e30cb7e71a861cd3bd4815e69 Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Thu, 2 Nov 2023 13:08:07 +0100 Subject: [PATCH 17/35] Add tests for ApplicationCultureInfo --- .../ApplicationCultureInfoTests.cs | 109 ++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 Tests/SonarScanner.MSBuild.TFS.Test/ApplicationCultureInfoTests.cs diff --git a/Tests/SonarScanner.MSBuild.TFS.Test/ApplicationCultureInfoTests.cs b/Tests/SonarScanner.MSBuild.TFS.Test/ApplicationCultureInfoTests.cs new file mode 100644 index 000000000..99694b73d --- /dev/null +++ b/Tests/SonarScanner.MSBuild.TFS.Test/ApplicationCultureInfoTests.cs @@ -0,0 +1,109 @@ +/* + * SonarScanner for .NET + * Copyright (C) 2016-2023 SonarSource SA + * mailto: info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +using System; +using System.Globalization; +using System.Threading; +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using SonarScanner.MSBuild.Common; + +namespace SonarScanner.MSBuild.TFS.Tests +{ + [TestClass] + public class ApplicationCultureInfoTests + { + // Don't run these tests in parallel as they are mutating global state + private static readonly Mutex Mutex = new(); + + [TestMethod] + public void ApplicationCultureInfoSetAndResetCultureWithUsing() + { + var previous = CultureInfo.DefaultThreadCurrentCulture; + var enUs = CultureInfo.GetCultureInfo("en-US"); + var deDe = CultureInfo.GetCultureInfo("de-DE"); + CultureInfo.DefaultThreadCurrentCulture = deDe; + try + { + CultureInfo.DefaultThreadCurrentCulture.Should().Be(deDe); + using (var sut = new ApplicationCultureInfo(enUs)) + { + CultureInfo.DefaultThreadCurrentCulture.Should().Be(enUs); + } + CultureInfo.DefaultThreadCurrentCulture.Should().Be(deDe); + } + finally + { + CultureInfo.DefaultThreadCurrentCulture = previous; + } + } + + [TestMethod] + public void ApplicationCultureInfoSetAndResetCultureManual() + { + var previous = CultureInfo.DefaultThreadCurrentCulture; + var enUs = CultureInfo.GetCultureInfo("en-US"); + var deDe = CultureInfo.GetCultureInfo("de-DE"); + CultureInfo.DefaultThreadCurrentCulture = deDe; + try + { + CultureInfo.DefaultThreadCurrentCulture.Should().Be(deDe); + var sut = new ApplicationCultureInfo(enUs); + CultureInfo.DefaultThreadCurrentCulture.Should().Be(enUs); + sut.Dispose(); + CultureInfo.DefaultThreadCurrentCulture.Should().Be(deDe); + } + finally + { + CultureInfo.DefaultThreadCurrentCulture = previous; + } + } + + [TestMethod] + [ExpectedException(typeof(InvalidOperationException))] + public void ApplicationCultureInfoSetAndResetCultureOnFailure() + { + var previous = CultureInfo.DefaultThreadCurrentCulture; + var enUs = CultureInfo.GetCultureInfo("en-US"); + var deDe = CultureInfo.GetCultureInfo("de-DE"); + CultureInfo.DefaultThreadCurrentCulture = deDe; + try + { + CultureInfo.DefaultThreadCurrentCulture.Should().Be(deDe); + using var _ = new ApplicationCultureInfo(enUs); + CultureInfo.DefaultThreadCurrentCulture.Should().Be(enUs); + throw new InvalidOperationException(); + } + finally + { + CultureInfo.DefaultThreadCurrentCulture.Should().Be(deDe); + CultureInfo.DefaultThreadCurrentCulture = previous; + } + } + + [TestInitialize] + public void PerformSetup() => + Mutex.WaitOne(); + + [TestCleanup] + public void PerformTeardown() => + Mutex.ReleaseMutex(); + } +} From c79a1aa5ee2985bcc250cd99be435f3b7a8daa8e Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Thu, 2 Nov 2023 14:51:51 +0100 Subject: [PATCH 18/35] Remove "TestFile" --- .../BinaryToXmlCoverageReportConverterTests.cs | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs b/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs index d87499aa4..3fa65a607 100644 --- a/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs +++ b/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs @@ -204,19 +204,5 @@ private static IVisualStudioSetupConfigurationFactory CreateVisualStudioSetupCon } #endregion Tests - - private sealed class TestFile : IDisposable - { - private readonly string filePath; - - public TestFile(string filePath) - { - this.filePath = filePath; - using var f = File.Create(filePath); - } - - public void Dispose() => - File.Delete(filePath); - } } } From 9b67c1dcc75cae85aaec89afd67b8cf06bbf4f9c Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Thu, 2 Nov 2023 14:53:14 +0100 Subject: [PATCH 19/35] Remove CreateVisualStudioSetupConfigurationFactory() --- ...BinaryToXmlCoverageReportConverterTests.cs | 58 +------------------ 1 file changed, 1 insertion(+), 57 deletions(-) diff --git a/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs b/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs index 3fa65a607..775ace2fb 100644 --- a/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs +++ b/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs @@ -146,63 +146,7 @@ public void Conv_ConvertToXml_ToolConvertsSampleFile() actualContent.Should().BeEquivalentTo(expectedContent); } - private static IVisualStudioSetupConfigurationFactory CreateVisualStudioSetupConfigurationFactory(string packageId) - { - var calls = 0; - var fetched = 1; - var noFetch = 0; - - // We need to do this kind of trickery because Moq cannot setup a callback for a method with an out parameter. - Func setupInstance = instances => - { - if (calls > 0) - { - return false; - } - - var package = Mock.Of(); - Mock.Get(package) - .Setup(x => x.GetId()) - .Returns(packageId); - - var instanceMock = new Mock(); - instanceMock - .Setup(_ => _.GetPackages()) - .Returns(new[] { package }); - instanceMock - .Setup(_ => _.GetInstallationVersion()) - .Returns("42"); - instanceMock - .Setup(_ => _.GetInstallationPath()) - .Returns("x:\\foo"); - - instances[0] = instanceMock.Object; - calls++; - - return true; - }; - - Func isSecondCall = _ => (calls > 0); - - var enumInstances = Mock.Of(); - Mock.Get(enumInstances) - .Setup(_ => _.Next(It.IsAny(), It.Is(x => isSecondCall(x)), out noFetch)); - Mock.Get(enumInstances) - .Setup(_ => _.Next(It.IsAny(), It.Is(x => setupInstance(x)), out fetched)); - - var configuration = Mock.Of(); - Mock.Get(configuration) - .Setup(_ => _.EnumInstances()) - .Returns(enumInstances); - - var factory = Mock.Of(); - Mock.Get(factory) - .Setup(_ => _.GetSetupConfigurationQuery()) - .Returns(configuration); - - return factory; - } - #endregion Tests + } } From 9ef17b1d9c318e8fde836fbad65176de64226619 Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Thu, 2 Nov 2023 14:55:19 +0100 Subject: [PATCH 20/35] Add Conv_ConvertToXml_ToolConvertsSampleFile_ProblematicCulture --- ...BinaryToXmlCoverageReportConverterTests.cs | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs b/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs index 775ace2fb..036bb7e96 100644 --- a/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs +++ b/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs @@ -19,6 +19,7 @@ */ using System; +using System.Globalization; using System.IO; using System.Linq; using System.Xml.Linq; @@ -146,6 +147,35 @@ public void Conv_ConvertToXml_ToolConvertsSampleFile() actualContent.Should().BeEquivalentTo(expectedContent); } + [TestMethod] + [DeploymentItem(@"Resources\Sample.coverage")] + [DeploymentItem(@"Resources\Expected.xmlcoverage")] + public void Conv_ConvertToXml_ToolConvertsSampleFile_ProblematicCulture() + { + // Arrange + var logger = new TestLogger(); + var config = new AnalysisConfig(); + var reporter = new BinaryToXmlCoverageReportConverter(logger, config); + var inputFilePath = $"{Environment.CurrentDirectory}\\Sample.coverage"; + var outputFilePath = $"{Environment.CurrentDirectory}\\Sample.xmlcoverage"; + var expectedOutputFilePath = $"{Environment.CurrentDirectory}\\Expected.xmlcoverage"; + File.Exists(inputFilePath).Should().BeTrue(); + File.Exists(outputFilePath).Should().BeFalse(); + File.Exists(expectedOutputFilePath).Should().BeTrue(); + using var _ = new ApplicationCultureInfo(CultureInfo.GetCultureInfo("de-DE")); // Serializes block_coverage="33.33" as block_coverage="33,33" + + // Act + var actual = reporter.ConvertToXml(inputFilePath, outputFilePath); + + // Assert + actual.Should().BeTrue(); + File.Exists(outputFilePath).Should().BeTrue(); + var actualContent = XDocument.Load(outputFilePath); + var expectedContent = XDocument.Load(expectedOutputFilePath); + // All tags and attributes must appear in the same order for actual and expected. Comments, whitespace, and the like is ignored in the assertion. + actualContent.Should().BeEquivalentTo(expectedContent); + } + #endregion Tests } From b3097a48b139a49e0e9054a59a9311fe999293fb Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Thu, 2 Nov 2023 14:57:24 +0100 Subject: [PATCH 21/35] Remove CodeCoverageExeTestMethodAttribute --- .../CodeCoverageExeTestMethod.cs | 50 ------------------- 1 file changed, 50 deletions(-) delete mode 100644 Tests/TestUtilities/CodeCoverageExeTestMethod.cs diff --git a/Tests/TestUtilities/CodeCoverageExeTestMethod.cs b/Tests/TestUtilities/CodeCoverageExeTestMethod.cs deleted file mode 100644 index 3cc18fd21..000000000 --- a/Tests/TestUtilities/CodeCoverageExeTestMethod.cs +++ /dev/null @@ -1,50 +0,0 @@ -/* - * SonarScanner for .NET - * Copyright (C) 2016-2023 SonarSource SA - * mailto: info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -using System; -using System.IO; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace TestUtilities -{ - [AttributeUsage(AttributeTargets.Method)] - public sealed class CodeCoverageExeTestMethodAttribute : TestMethodAttribute - { - private const string EnvironmentVariable = "VsTestToolsInstallerInstalledToolLocation"; - - public override TestResult[] Execute(ITestMethod testMethod) => - FindCodeCoverageExe() is not null - ? base.Execute(testMethod) - : (new TestResult[] - { - new() - { - LogError = @$"CodeCoverage.exe wasn't found. Set the {EnvironmentVariable} to the path to CodeCoverage.exe. The tool can be downloaded and zip extracted from the Microsoft.CodeCoverage NuGet package. It is in the build\netstandard2.0\CodeCoverage folder in the package.", - Outcome = UnitTestOutcome.Inconclusive, - } - }); - - public static string FindCodeCoverageExe() => - Environment.GetEnvironmentVariable(EnvironmentVariable) is { } path - && File.Exists(path) - ? path - : null; - } -} From e974945fe0867f6de492f52d93fa6675a301441a Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Thu, 2 Nov 2023 15:03:41 +0100 Subject: [PATCH 22/35] Remove CONV_ERROR_OutputFileNotFound from resource --- .../Resources.Designer.cs | 9 --------- src/SonarScanner.MSBuild.TFS.Classic/Resources.resx | 3 --- 2 files changed, 12 deletions(-) diff --git a/src/SonarScanner.MSBuild.TFS.Classic/Resources.Designer.cs b/src/SonarScanner.MSBuild.TFS.Classic/Resources.Designer.cs index 7997e2e8f..f60df6be9 100644 --- a/src/SonarScanner.MSBuild.TFS.Classic/Resources.Designer.cs +++ b/src/SonarScanner.MSBuild.TFS.Classic/Resources.Designer.cs @@ -70,15 +70,6 @@ internal static string CONV_ERROR_ConversionToolFailed { } } - /// - /// Looks up a localized string similar to Failed to convert the binary coverage file to XML. The expected output file was not found: {0}. - /// - internal static string CONV_ERROR_OutputFileNotFound { - get { - return ResourceManager.GetString("CONV_ERROR_OutputFileNotFound", resourceCulture); - } - } - /// /// Looks up a localized string similar to Connected to {0}. /// diff --git a/src/SonarScanner.MSBuild.TFS.Classic/Resources.resx b/src/SonarScanner.MSBuild.TFS.Classic/Resources.resx index 066674044..e23e1a3be 100644 --- a/src/SonarScanner.MSBuild.TFS.Classic/Resources.resx +++ b/src/SonarScanner.MSBuild.TFS.Classic/Resources.resx @@ -121,9 +121,6 @@ Failed to convert the downloaded code coverage tool to XML. No code coverage information will be uploaded to SonarQube. Check that the downloaded code coverage file ({0}) is valid by opening it in Visual Studio. If it is not, check that the internet security settings on the build machine allow files to be downloaded from the Team Foundation Server machine. - - Failed to convert the binary coverage file to XML. The expected output file was not found: {0} - Connected to {0} From fca0d3fea35bdc7e24a87b4003709c6cfbf8e05a Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Thu, 2 Nov 2023 15:05:54 +0100 Subject: [PATCH 23/35] File header --- .../ApplicationCultureInfo.cs | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/src/SonarScanner.MSBuild.Common/ApplicationCultureInfo.cs b/src/SonarScanner.MSBuild.Common/ApplicationCultureInfo.cs index 0166e6c24..9fe31cacc 100644 --- a/src/SonarScanner.MSBuild.Common/ApplicationCultureInfo.cs +++ b/src/SonarScanner.MSBuild.Common/ApplicationCultureInfo.cs @@ -1,7 +1,25 @@ -using System; -using System.Collections.Generic; +/* + * SonarScanner for .NET + * Copyright (C) 2016-2023 SonarSource SA + * mailto: info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +using System; using System.Globalization; -using System.Text; namespace SonarScanner.MSBuild.Common { From 41044c93d72df5aca3531b300511a3182b5ec4d6 Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Thu, 2 Nov 2023 16:30:48 +0100 Subject: [PATCH 24/35] Nameout file after test to avoid collissions --- .../Classic/BinaryToXmlCoverageReportConverterTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs b/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs index 036bb7e96..cbc83c65d 100644 --- a/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs +++ b/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs @@ -129,7 +129,7 @@ public void Conv_ConvertToXml_ToolConvertsSampleFile() var config = new AnalysisConfig(); var reporter = new BinaryToXmlCoverageReportConverter(logger, config); var inputFilePath = $"{Environment.CurrentDirectory}\\Sample.coverage"; - var outputFilePath = $"{Environment.CurrentDirectory}\\Sample.xmlcoverage"; + var outputFilePath = $"{Environment.CurrentDirectory}\\{nameof(Conv_ConvertToXml_ToolConvertsSampleFile)}.xmlcoverage"; var expectedOutputFilePath = $"{Environment.CurrentDirectory}\\Expected.xmlcoverage"; File.Exists(inputFilePath).Should().BeTrue(); File.Exists(outputFilePath).Should().BeFalse(); @@ -157,7 +157,7 @@ public void Conv_ConvertToXml_ToolConvertsSampleFile_ProblematicCulture() var config = new AnalysisConfig(); var reporter = new BinaryToXmlCoverageReportConverter(logger, config); var inputFilePath = $"{Environment.CurrentDirectory}\\Sample.coverage"; - var outputFilePath = $"{Environment.CurrentDirectory}\\Sample.xmlcoverage"; + var outputFilePath = $"{Environment.CurrentDirectory}\\{nameof(Conv_ConvertToXml_ToolConvertsSampleFile_ProblematicCulture)}.xmlcoverage"; var expectedOutputFilePath = $"{Environment.CurrentDirectory}\\Expected.xmlcoverage"; File.Exists(inputFilePath).Should().BeTrue(); File.Exists(outputFilePath).Should().BeFalse(); From 4db2ccb3cf756a2fc5777e56a27d01abb509e997 Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Thu, 2 Nov 2023 17:56:56 +0100 Subject: [PATCH 25/35] Use DoNotParallelize --- .../ApplicationCultureInfoTests.cs | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/Tests/SonarScanner.MSBuild.TFS.Test/ApplicationCultureInfoTests.cs b/Tests/SonarScanner.MSBuild.TFS.Test/ApplicationCultureInfoTests.cs index 99694b73d..6286a9cff 100644 --- a/Tests/SonarScanner.MSBuild.TFS.Test/ApplicationCultureInfoTests.cs +++ b/Tests/SonarScanner.MSBuild.TFS.Test/ApplicationCultureInfoTests.cs @@ -28,11 +28,9 @@ namespace SonarScanner.MSBuild.TFS.Tests { [TestClass] + [DoNotParallelize] public class ApplicationCultureInfoTests { - // Don't run these tests in parallel as they are mutating global state - private static readonly Mutex Mutex = new(); - [TestMethod] public void ApplicationCultureInfoSetAndResetCultureWithUsing() { @@ -97,13 +95,5 @@ public void ApplicationCultureInfoSetAndResetCultureOnFailure() CultureInfo.DefaultThreadCurrentCulture = previous; } } - - [TestInitialize] - public void PerformSetup() => - Mutex.WaitOne(); - - [TestCleanup] - public void PerformTeardown() => - Mutex.ReleaseMutex(); } } From 728a41c2f1bc3d0d69825f5d19b8016470308b6a Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Thu, 2 Nov 2023 17:57:48 +0100 Subject: [PATCH 26/35] Unused using --- .../SonarScanner.MSBuild.TFS.Test/ApplicationCultureInfoTests.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Tests/SonarScanner.MSBuild.TFS.Test/ApplicationCultureInfoTests.cs b/Tests/SonarScanner.MSBuild.TFS.Test/ApplicationCultureInfoTests.cs index 6286a9cff..6acaa4e2d 100644 --- a/Tests/SonarScanner.MSBuild.TFS.Test/ApplicationCultureInfoTests.cs +++ b/Tests/SonarScanner.MSBuild.TFS.Test/ApplicationCultureInfoTests.cs @@ -20,7 +20,6 @@ using System; using System.Globalization; -using System.Threading; using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; using SonarScanner.MSBuild.Common; From 9a65d563156a56e3476ee3f588ca3396ef177926 Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Thu, 2 Nov 2023 17:58:47 +0100 Subject: [PATCH 27/35] Unused using, region --- .../Classic/BinaryToXmlCoverageReportConverterTests.cs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs b/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs index cbc83c65d..e19dad348 100644 --- a/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs +++ b/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs @@ -21,10 +21,8 @@ using System; using System.Globalization; using System.IO; -using System.Linq; using System.Xml.Linq; using FluentAssertions; -using Microsoft.VisualStudio.Setup.Configuration; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; using SonarScanner.MSBuild.Common; @@ -38,8 +36,6 @@ public class BinaryToXmlCoverageReportConverterTests { public TestContext TestContext { get; set; } - #region Tests - [TestMethod] public void Conv_Ctor_InvalidArgs_Throws() { @@ -175,8 +171,5 @@ public void Conv_ConvertToXml_ToolConvertsSampleFile_ProblematicCulture() // All tags and attributes must appear in the same order for actual and expected. Comments, whitespace, and the like is ignored in the assertion. actualContent.Should().BeEquivalentTo(expectedContent); } - - #endregion Tests - } } From 797204da412831b9d9ba1c46f4f926885658feaa Mon Sep 17 00:00:00 2001 From: Martin Strecker <103252490+martin-strecker-sonarsource@users.noreply.github.com> Date: Thu, 2 Nov 2023 18:02:39 +0100 Subject: [PATCH 28/35] Apply suggestions from code review Co-authored-by: Costin Zaharia <56015273+costin-zaharia-sonarsource@users.noreply.github.com> --- .../Classic/BinaryToXmlCoverageReportConverterTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs b/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs index e19dad348..4852bbf06 100644 --- a/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs +++ b/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs @@ -67,7 +67,7 @@ public void Conv_ConvertToXml_InvalidArgs_Throws() [TestMethod] [WorkItem(72)] // Regression test for bug #72: CodeCoverage conversion - conversion errors should be detected and reported - public void Conv_ConvertionFailure_Success_False_And_ErrorLogged() + public void Conv_ConversionFailure_Success_False_And_ErrorLogged() { // Arrange var logger = new TestLogger(); @@ -86,7 +86,7 @@ public void Conv_ConvertionFailure_Success_False_And_ErrorLogged() File.Exists(outputFilePath).Should().BeFalse("Conversion failed"); - logger.AssertErrorLogged(@$"Failed to convert the downloaded code coverage tool to XML. No code coverage information will be uploaded to SonarQube. + logger.AssertErrorLogged(@$"Failed to convert the identified code coverage file to XML. No code coverage information will be uploaded to SonarQube. Check that the downloaded code coverage file ({inputFilePath}) is valid by opening it in Visual Studio. If it is not, check that the internet security settings on the build machine allow files to be downloaded from the Team Foundation Server machine."); logger.AssertNoWarningsLogged(); } From db680bb1aa7e63b18f2fc94254c22a0f1d16375b Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Thu, 2 Nov 2023 18:05:24 +0100 Subject: [PATCH 29/35] Fix message --- src/SonarScanner.MSBuild.TFS.Classic/Resources.Designer.cs | 2 +- src/SonarScanner.MSBuild.TFS.Classic/Resources.resx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/SonarScanner.MSBuild.TFS.Classic/Resources.Designer.cs b/src/SonarScanner.MSBuild.TFS.Classic/Resources.Designer.cs index f60df6be9..0db95715a 100644 --- a/src/SonarScanner.MSBuild.TFS.Classic/Resources.Designer.cs +++ b/src/SonarScanner.MSBuild.TFS.Classic/Resources.Designer.cs @@ -61,7 +61,7 @@ internal Resources() { } /// - /// Looks up a localized string similar to Failed to convert the downloaded code coverage tool to XML. No code coverage information will be uploaded to SonarQube. + /// Looks up a localized string similar to Failed to convert the identified code coverage file to XML. No code coverage information will be uploaded to SonarQube. ///Check that the downloaded code coverage file ({0}) is valid by opening it in Visual Studio. If it is not, check that the internet security settings on the build machine allow files to be downloaded from the Team Foundation Server machine.. /// internal static string CONV_ERROR_ConversionToolFailed { diff --git a/src/SonarScanner.MSBuild.TFS.Classic/Resources.resx b/src/SonarScanner.MSBuild.TFS.Classic/Resources.resx index e23e1a3be..7daa560e9 100644 --- a/src/SonarScanner.MSBuild.TFS.Classic/Resources.resx +++ b/src/SonarScanner.MSBuild.TFS.Classic/Resources.resx @@ -118,7 +118,7 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - Failed to convert the downloaded code coverage tool to XML. No code coverage information will be uploaded to SonarQube. + Failed to convert the identified code coverage file to XML. No code coverage information will be uploaded to SonarQube. Check that the downloaded code coverage file ({0}) is valid by opening it in Visual Studio. If it is not, check that the internet security settings on the build machine allow files to be downloaded from the Team Foundation Server machine. From 958d79b0bd064371093befe7912995b878381683 Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Fri, 3 Nov 2023 12:29:22 +0100 Subject: [PATCH 30/35] using simplification --- .../ApplicationCultureInfoTests.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Tests/SonarScanner.MSBuild.TFS.Test/ApplicationCultureInfoTests.cs b/Tests/SonarScanner.MSBuild.TFS.Test/ApplicationCultureInfoTests.cs index 6acaa4e2d..bf7c9b1ba 100644 --- a/Tests/SonarScanner.MSBuild.TFS.Test/ApplicationCultureInfoTests.cs +++ b/Tests/SonarScanner.MSBuild.TFS.Test/ApplicationCultureInfoTests.cs @@ -40,7 +40,7 @@ public void ApplicationCultureInfoSetAndResetCultureWithUsing() try { CultureInfo.DefaultThreadCurrentCulture.Should().Be(deDe); - using (var sut = new ApplicationCultureInfo(enUs)) + using (new ApplicationCultureInfo(enUs)) { CultureInfo.DefaultThreadCurrentCulture.Should().Be(enUs); } @@ -84,9 +84,11 @@ public void ApplicationCultureInfoSetAndResetCultureOnFailure() try { CultureInfo.DefaultThreadCurrentCulture.Should().Be(deDe); - using var _ = new ApplicationCultureInfo(enUs); - CultureInfo.DefaultThreadCurrentCulture.Should().Be(enUs); - throw new InvalidOperationException(); + using (new ApplicationCultureInfo(enUs)) + { + CultureInfo.DefaultThreadCurrentCulture.Should().Be(enUs); + throw new InvalidOperationException(); + } } finally { From 48e5bfe5544292174740086883f2cfafcf9b092d Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Fri, 3 Nov 2023 12:41:06 +0100 Subject: [PATCH 31/35] Change to VanguardException --- .../BinaryToXmlCoverageReportConverter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SonarScanner.MSBuild.TFS.Classic/BinaryToXmlCoverageReportConverter.cs b/src/SonarScanner.MSBuild.TFS.Classic/BinaryToXmlCoverageReportConverter.cs index d9e83d034..a7d06a2ed 100644 --- a/src/SonarScanner.MSBuild.TFS.Classic/BinaryToXmlCoverageReportConverter.cs +++ b/src/SonarScanner.MSBuild.TFS.Classic/BinaryToXmlCoverageReportConverter.cs @@ -84,7 +84,7 @@ public static bool ConvertBinaryToXml(string inputBinaryFilePath, string outputX includeSkippedFunctions: false, includeSkippedModules: false); } - catch (AggregateException aggregate) when (aggregate.InnerException is InvalidCoverageFileException) + catch (AggregateException aggregate) when (aggregate.InnerException is VanguardException) { logger.LogError(Resources.CONV_ERROR_ConversionToolFailed, inputBinaryFilePath); return false; From 8bb576ba7fec003acf9397be1f0a61c61f9a1099 Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Fri, 3 Nov 2023 12:50:52 +0100 Subject: [PATCH 32/35] Formatting --- .../BinaryToXmlCoverageReportConverter.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/SonarScanner.MSBuild.TFS.Classic/BinaryToXmlCoverageReportConverter.cs b/src/SonarScanner.MSBuild.TFS.Classic/BinaryToXmlCoverageReportConverter.cs index a7d06a2ed..c68f67d52 100644 --- a/src/SonarScanner.MSBuild.TFS.Classic/BinaryToXmlCoverageReportConverter.cs +++ b/src/SonarScanner.MSBuild.TFS.Classic/BinaryToXmlCoverageReportConverter.cs @@ -67,8 +67,7 @@ public bool ConvertToXml(string inputFilePath, string outputFilePath) #endregion IReportConverter interface // was internal - public static bool ConvertBinaryToXml(string inputBinaryFilePath, string outputXmlFilePath, - ILogger logger) + public static bool ConvertBinaryToXml(string inputBinaryFilePath, string outputXmlFilePath, ILogger logger) { Debug.Assert(Path.IsPathRooted(inputBinaryFilePath), "Expecting the input file name to be a full absolute path"); Debug.Assert(File.Exists(inputBinaryFilePath), "Expecting the input file to exist: " + inputBinaryFilePath); From d53e008736d71a22461bf2625210ff6ebd6d19e5 Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Fri, 3 Nov 2023 15:16:06 +0100 Subject: [PATCH 33/35] Inline static ConvertBinaryToXml to ConvertToXml --- ...BinaryToXmlCoverageReportConverterTests.cs | 17 +++++----- .../BinaryToXmlCoverageReportConverter.cs | 31 +++---------------- .../Program.cs | 2 +- .../TfsLegacyCoverageReportProcessor.cs | 2 +- 4 files changed, 15 insertions(+), 37 deletions(-) diff --git a/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs b/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs index 4852bbf06..8439756e0 100644 --- a/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs +++ b/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs @@ -39,7 +39,7 @@ public class BinaryToXmlCoverageReportConverterTests [TestMethod] public void Conv_Ctor_InvalidArgs_Throws() { - Action op = () => new BinaryToXmlCoverageReportConverter(null, new AnalysisConfig()); + Action op = () => new BinaryToXmlCoverageReportConverter(null); op.Should().Throw().And.ParamName.Should().Be("logger"); } @@ -47,8 +47,7 @@ public void Conv_Ctor_InvalidArgs_Throws() [TestMethod] public void Conv_ConvertToXml_InvalidArgs_Throws() { - ILogger loggerMock = new Mock().Object; - var testSubject = new BinaryToXmlCoverageReportConverter(loggerMock, new AnalysisConfig()); + var testSubject = new BinaryToXmlCoverageReportConverter(Mock.Of()); // 1. Null input path Action op = () => testSubject.ConvertToXml(null, "dummypath"); @@ -71,6 +70,7 @@ public void Conv_ConversionFailure_Success_False_And_ErrorLogged() { // Arrange var logger = new TestLogger(); + var sut = new BinaryToXmlCoverageReportConverter(logger); var testDir = TestUtils.CreateTestSpecificFolderWithSubPaths(TestContext); var outputFilePath = Path.Combine(testDir, "output.txt"); @@ -79,7 +79,7 @@ public void Conv_ConversionFailure_Success_False_And_ErrorLogged() File.WriteAllText(inputFilePath, "dummy input file"); // Act - var success = BinaryToXmlCoverageReportConverter.ConvertBinaryToXml(inputFilePath, outputFilePath, logger); + var success = sut.ConvertToXml(inputFilePath, outputFilePath); // Assert success.Should().BeFalse(); @@ -97,6 +97,7 @@ public void Conv_FailsIfFileConverterReturnsAnErrorCode() { // Arrange var logger = new TestLogger(); + var sut = new BinaryToXmlCoverageReportConverter(logger); var testDir = TestUtils.CreateTestSpecificFolderWithSubPaths(TestContext); var outputFilePath = Path.Combine(testDir, "output.txt"); @@ -105,7 +106,7 @@ public void Conv_FailsIfFileConverterReturnsAnErrorCode() File.WriteAllText(inputFilePath, "dummy input file"); // Act - var success = BinaryToXmlCoverageReportConverter.ConvertBinaryToXml(inputFilePath, outputFilePath, logger); + var success = sut.ConvertToXml(inputFilePath, outputFilePath); // Assert success.Should().BeFalse("Expecting the process to fail"); @@ -122,8 +123,7 @@ public void Conv_ConvertToXml_ToolConvertsSampleFile() { // Arrange var logger = new TestLogger(); - var config = new AnalysisConfig(); - var reporter = new BinaryToXmlCoverageReportConverter(logger, config); + var reporter = new BinaryToXmlCoverageReportConverter(logger); var inputFilePath = $"{Environment.CurrentDirectory}\\Sample.coverage"; var outputFilePath = $"{Environment.CurrentDirectory}\\{nameof(Conv_ConvertToXml_ToolConvertsSampleFile)}.xmlcoverage"; var expectedOutputFilePath = $"{Environment.CurrentDirectory}\\Expected.xmlcoverage"; @@ -150,8 +150,7 @@ public void Conv_ConvertToXml_ToolConvertsSampleFile_ProblematicCulture() { // Arrange var logger = new TestLogger(); - var config = new AnalysisConfig(); - var reporter = new BinaryToXmlCoverageReportConverter(logger, config); + var reporter = new BinaryToXmlCoverageReportConverter(logger); var inputFilePath = $"{Environment.CurrentDirectory}\\Sample.coverage"; var outputFilePath = $"{Environment.CurrentDirectory}\\{nameof(Conv_ConvertToXml_ToolConvertsSampleFile_ProblematicCulture)}.xmlcoverage"; var expectedOutputFilePath = $"{Environment.CurrentDirectory}\\Expected.xmlcoverage"; diff --git a/src/SonarScanner.MSBuild.TFS.Classic/BinaryToXmlCoverageReportConverter.cs b/src/SonarScanner.MSBuild.TFS.Classic/BinaryToXmlCoverageReportConverter.cs index c68f67d52..4016663df 100644 --- a/src/SonarScanner.MSBuild.TFS.Classic/BinaryToXmlCoverageReportConverter.cs +++ b/src/SonarScanner.MSBuild.TFS.Classic/BinaryToXmlCoverageReportConverter.cs @@ -32,22 +32,11 @@ public class BinaryToXmlCoverageReportConverter : ICoverageReportConverter { private readonly ILogger logger; - #region Public methods - - public BinaryToXmlCoverageReportConverter(ILogger logger, AnalysisConfig config) - : this(new VisualStudioSetupConfigurationFactory(), logger, config) - { } - - public BinaryToXmlCoverageReportConverter(IVisualStudioSetupConfigurationFactory setupConfigurationFactory, - ILogger logger, AnalysisConfig config) + public BinaryToXmlCoverageReportConverter(ILogger logger) { this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); } - #endregion Public methods - - #region IReportConverter interface - public bool Initialize() => true; public bool ConvertToXml(string inputFilePath, string outputFilePath) @@ -61,31 +50,21 @@ public bool ConvertToXml(string inputFilePath, string outputFilePath) throw new ArgumentNullException(nameof(outputFilePath)); } - return ConvertBinaryToXml(inputFilePath, outputFilePath, logger); - } - - #endregion IReportConverter interface - - // was internal - public static bool ConvertBinaryToXml(string inputBinaryFilePath, string outputXmlFilePath, ILogger logger) - { - Debug.Assert(Path.IsPathRooted(inputBinaryFilePath), "Expecting the input file name to be a full absolute path"); - Debug.Assert(File.Exists(inputBinaryFilePath), "Expecting the input file to exist: " + inputBinaryFilePath); - Debug.Assert(Path.IsPathRooted(outputXmlFilePath), "Expecting the output file name to be a full absolute path"); + Debug.Assert(File.Exists(inputFilePath), "Expecting the input file to exist: " + inputFilePath); var util = new CoverageFileUtility(); try { using var dummy = new ApplicationCultureInfo(CultureInfo.InvariantCulture); util.ConvertCoverageFile( - path: inputBinaryFilePath, - outputPath: outputXmlFilePath, + path: inputFilePath, + outputPath: outputFilePath, includeSkippedFunctions: false, includeSkippedModules: false); } catch (AggregateException aggregate) when (aggregate.InnerException is VanguardException) { - logger.LogError(Resources.CONV_ERROR_ConversionToolFailed, inputBinaryFilePath); + logger.LogError(Resources.CONV_ERROR_ConversionToolFailed, inputFilePath); return false; } return true; diff --git a/src/SonarScanner.MSBuild.TFS.Classic/Program.cs b/src/SonarScanner.MSBuild.TFS.Classic/Program.cs index 5a3b1b759..fbadf54ce 100644 --- a/src/SonarScanner.MSBuild.TFS.Classic/Program.cs +++ b/src/SonarScanner.MSBuild.TFS.Classic/Program.cs @@ -91,7 +91,7 @@ private static void ExecuteReportBuilder(ILogger logger, private static void ExecuteCoverageConverter(ILogger logger, AnalysisConfig config, ILegacyTeamBuildFactory teamBuildFactory, IBuildSettings buildSettings, string fullPropertiesFilePath) { - var binaryConverter = new BinaryToXmlCoverageReportConverter(logger, config); + var binaryConverter = new BinaryToXmlCoverageReportConverter(logger); var coverageReportProcessor = new CoverageReportProcessor(teamBuildFactory, binaryConverter, logger); if (coverageReportProcessor.Initialise(config, buildSettings, fullPropertiesFilePath)) diff --git a/src/SonarScanner.MSBuild.TFS.Classic/XamlBuild/TfsLegacyCoverageReportProcessor.cs b/src/SonarScanner.MSBuild.TFS.Classic/XamlBuild/TfsLegacyCoverageReportProcessor.cs index 3af8f1547..9f7c60dce 100644 --- a/src/SonarScanner.MSBuild.TFS.Classic/XamlBuild/TfsLegacyCoverageReportProcessor.cs +++ b/src/SonarScanner.MSBuild.TFS.Classic/XamlBuild/TfsLegacyCoverageReportProcessor.cs @@ -37,7 +37,7 @@ public class TfsLegacyCoverageReportProcessor : CoverageReportProcessorBase public TfsLegacyCoverageReportProcessor(ILogger logger, AnalysisConfig config) : this(new CoverageReportUrlProvider(logger), new CoverageReportDownloader(logger), - new BinaryToXmlCoverageReportConverter(logger, config), logger) + new BinaryToXmlCoverageReportConverter(logger), logger) { } From d496ddc789344b679030f44038406896f30569c2 Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Fri, 3 Nov 2023 16:51:31 +0100 Subject: [PATCH 34/35] Add support for file related expetions and tests --- ...BinaryToXmlCoverageReportConverterTests.cs | 58 +++++++++++++++++++ .../BinaryToXmlCoverageReportConverter.cs | 7 ++- .../Resources.Designer.cs | 9 +++ .../Resources.resx | 3 + 4 files changed, 75 insertions(+), 2 deletions(-) diff --git a/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs b/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs index 8439756e0..12d61d159 100644 --- a/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs +++ b/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs @@ -116,6 +116,64 @@ public void Conv_FailsIfFileConverterReturnsAnErrorCode() File.Exists(outputFilePath).Should().BeFalse("Not expecting the output file to exist"); } + [TestMethod] + public void Conv_FailsIfInputFileDoesNotExists() + { + // Arrange + var logger = new TestLogger(); + var sut = new BinaryToXmlCoverageReportConverter(logger); + var testDir = TestUtils.CreateTestSpecificFolderWithSubPaths(TestContext); + + var outputFilePath = Path.Combine(testDir, "output.txt"); + + var inputFilePath = Path.Combine(testDir, "input.txt"); + + // Act + var success = sut.ConvertToXml(inputFilePath, outputFilePath); + + // Assert + success.Should().BeFalse("Expecting the process to fail"); + logger.Errors.Should().ContainSingle().Which.Should().Be(@$"The binary coverage file {inputFilePath} could not be found. No coverage information will be uploaded to the Sonar server."); + + File.Exists(outputFilePath).Should().BeFalse("Not expecting the output file to exist"); + } + + [TestMethod] + public void Conv_FailsIfInputFileIsLocked() + { + // Arrange + var logger = new TestLogger(); + var sut = new BinaryToXmlCoverageReportConverter(logger); + var testDir = TestUtils.CreateTestSpecificFolderWithSubPaths(TestContext); + + var outputFilePath = Path.Combine(testDir, "output.txt"); + + var inputFilePath = Path.Combine(testDir, "input.txt"); + File.WriteAllText(inputFilePath, "Some content"); + try + { + using var fs = new FileStream(inputFilePath, FileMode.Open, FileAccess.ReadWrite, FileShare.None); // lock the file with FileShare.None + + // FileShare.None will cause nested inner exceptions: AggregateException -> CoverageFileException -> IOException with messages + // AggregateException: One or more errors occurred. + // CoverageFileException: Failed to open coverage file "C:\Fullpath\input.txt". + // IOException: The process cannot access the file 'C:\Fullpath\input.txt' because it is being used by another process. + + // Act + var success = sut.ConvertToXml(inputFilePath, outputFilePath); + + // Assert + success.Should().BeFalse("Expecting the process to fail"); + logger.Errors.Should().ContainSingle().Which.Should().Match(@$"Failed to convert the identified code coverage file to XML. No code coverage information will be uploaded to SonarQube.*Check that the downloaded code coverage file ({inputFilePath}) is valid by opening it in Visual Studio. If it is not, check that the internet security settings on the build machine allow files to be downloaded from the Team Foundation Server machine."); + + File.Exists(outputFilePath).Should().BeFalse("Not expecting the output file to exist"); + } + finally + { + File.Delete(inputFilePath); + } + } + [TestMethod] [DeploymentItem(@"Resources\Sample.coverage")] [DeploymentItem(@"Resources\Expected.xmlcoverage")] diff --git a/src/SonarScanner.MSBuild.TFS.Classic/BinaryToXmlCoverageReportConverter.cs b/src/SonarScanner.MSBuild.TFS.Classic/BinaryToXmlCoverageReportConverter.cs index 4016663df..59686389d 100644 --- a/src/SonarScanner.MSBuild.TFS.Classic/BinaryToXmlCoverageReportConverter.cs +++ b/src/SonarScanner.MSBuild.TFS.Classic/BinaryToXmlCoverageReportConverter.cs @@ -49,8 +49,11 @@ public bool ConvertToXml(string inputFilePath, string outputFilePath) { throw new ArgumentNullException(nameof(outputFilePath)); } - - Debug.Assert(File.Exists(inputFilePath), "Expecting the input file to exist: " + inputFilePath); + if (!File.Exists(inputFilePath)) + { + logger.LogError(Resources.CONV_ERROR_InputFileNotFound, inputFilePath); + return false; + } var util = new CoverageFileUtility(); try diff --git a/src/SonarScanner.MSBuild.TFS.Classic/Resources.Designer.cs b/src/SonarScanner.MSBuild.TFS.Classic/Resources.Designer.cs index 0db95715a..46ace00d9 100644 --- a/src/SonarScanner.MSBuild.TFS.Classic/Resources.Designer.cs +++ b/src/SonarScanner.MSBuild.TFS.Classic/Resources.Designer.cs @@ -70,6 +70,15 @@ internal static string CONV_ERROR_ConversionToolFailed { } } + /// + /// Looks up a localized string similar to The binary coverage file {0} could not be found. No coverage information will be uploaded to the Sonar server.. + /// + internal static string CONV_ERROR_InputFileNotFound { + get { + return ResourceManager.GetString("CONV_ERROR_InputFileNotFound", resourceCulture); + } + } + /// /// Looks up a localized string similar to Connected to {0}. /// diff --git a/src/SonarScanner.MSBuild.TFS.Classic/Resources.resx b/src/SonarScanner.MSBuild.TFS.Classic/Resources.resx index 7daa560e9..c307169ec 100644 --- a/src/SonarScanner.MSBuild.TFS.Classic/Resources.resx +++ b/src/SonarScanner.MSBuild.TFS.Classic/Resources.resx @@ -121,6 +121,9 @@ Failed to convert the identified code coverage file to XML. No code coverage information will be uploaded to SonarQube. Check that the downloaded code coverage file ({0}) is valid by opening it in Visual Studio. If it is not, check that the internet security settings on the build machine allow files to be downloaded from the Team Foundation Server machine. + + The binary coverage file {0} could not be found. No coverage information will be uploaded to the Sonar server. + Connected to {0} From fda2c9fd1cdc46f1ab934ddd15641456d0a4ff83 Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Fri, 3 Nov 2023 16:56:45 +0100 Subject: [PATCH 35/35] Fix test file isolation issues --- .../Classic/BinaryToXmlCoverageReportConverterTests.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs b/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs index 12d61d159..c59c9f70a 100644 --- a/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs +++ b/Tests/SonarScanner.MSBuild.TFS.Test/Classic/BinaryToXmlCoverageReportConverterTests.cs @@ -32,6 +32,7 @@ namespace SonarScanner.MSBuild.TFS.Tests { [TestClass] + [DoNotParallelize] public class BinaryToXmlCoverageReportConverterTests { public TestContext TestContext { get; set; } @@ -75,7 +76,7 @@ public void Conv_ConversionFailure_Success_False_And_ErrorLogged() var outputFilePath = Path.Combine(testDir, "output.txt"); - var inputFilePath = Path.Combine(testDir, "input.txt"); + var inputFilePath = Path.Combine(testDir, $"input_{nameof(Conv_ConversionFailure_Success_False_And_ErrorLogged)}.txt"); File.WriteAllText(inputFilePath, "dummy input file"); // Act @@ -102,7 +103,7 @@ public void Conv_FailsIfFileConverterReturnsAnErrorCode() var outputFilePath = Path.Combine(testDir, "output.txt"); - var inputFilePath = Path.Combine(testDir, "input.txt"); + var inputFilePath = Path.Combine(testDir, $"input_{nameof(Conv_FailsIfFileConverterReturnsAnErrorCode)}.txt"); File.WriteAllText(inputFilePath, "dummy input file"); // Act @@ -126,7 +127,7 @@ public void Conv_FailsIfInputFileDoesNotExists() var outputFilePath = Path.Combine(testDir, "output.txt"); - var inputFilePath = Path.Combine(testDir, "input.txt"); + var inputFilePath = Path.Combine(testDir, $"input_{nameof(Conv_FailsIfInputFileDoesNotExists)}.txt"); // Act var success = sut.ConvertToXml(inputFilePath, outputFilePath); @@ -148,7 +149,7 @@ public void Conv_FailsIfInputFileIsLocked() var outputFilePath = Path.Combine(testDir, "output.txt"); - var inputFilePath = Path.Combine(testDir, "input.txt"); + var inputFilePath = Path.Combine(testDir, $"input_{nameof(Conv_FailsIfInputFileIsLocked)}.txt"); File.WriteAllText(inputFilePath, "Some content"); try {