1717 * along with this program; if not, write to the Free Software Foundation,
1818 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
1919 */
20-
20+
2121using Microsoft . Win32 ;
2222using SonarQube . Common ;
2323using System ;
2626using System . IO ;
2727using System . Linq ;
2828using System . Text . RegularExpressions ;
29+ using Microsoft . VisualStudio . Setup . Configuration ;
2930
3031namespace SonarQube . TeamBuild . Integration
3132{
3233 public class CoverageReportConverter : ICoverageReportConverter
3334 {
3435 private const int ConversionTimeoutInMs = 60000 ;
36+ private readonly IVisualStudioSetupConfigurationFactory setupConfigurationFactory ;
3537
3638 /// <summary>
3739 /// Registry containing information about installed VS versions
@@ -43,8 +45,26 @@ public class CoverageReportConverter : ICoverageReportConverter
4345 /// </summary>
4446 private const string TeamToolPathandExeName = @"Team Tools\Dynamic Code Coverage Tools\CodeCoverage.exe" ;
4547
48+ /// <summary>
49+ /// Code coverage package name for Visual Studio setup configuration
50+ /// </summary>
51+ private const string CodeCoverageInstallationPackage = "Microsoft.VisualStudio.TestTools.CodeCoverage" ;
52+
4653 private string conversionToolPath ;
4754
55+ #region Public methods
56+
57+ public CoverageReportConverter ( )
58+ : this ( new VisualStudioSetupConfigurationFactory ( ) )
59+ { }
60+
61+ public CoverageReportConverter ( IVisualStudioSetupConfigurationFactory setupConfigurationFactory )
62+ {
63+ this . setupConfigurationFactory = setupConfigurationFactory ;
64+ }
65+
66+ #endregion Public methods
67+
4868 #region IReportConverter interface
4969
5070 public bool Initialize ( ILogger logger )
@@ -94,11 +114,76 @@ public bool ConvertToXml(string inputFilePath, string outputFilePath, ILogger lo
94114
95115 #region Private methods
96116
97- private static string GetExeToolPath ( ILogger logger )
117+ private string GetExeToolPath ( ILogger logger )
118+ {
119+ logger . LogDebug ( Resources . CONV_DIAG_LocatingCodeCoverageTool ) ;
120+ return GetExeToolPathFromSetupConfiguration ( logger ) ??
121+ GetExeToolPathFromRegistry ( logger ) ;
122+ }
123+
124+ #region Code Coverage Tool path from setup configuration
125+
126+ private string GetExeToolPathFromSetupConfiguration ( ILogger logger )
98127 {
99128 string toolPath = null ;
100129
101- logger . LogDebug ( Resources . CONV_DIAG_LocatingCodeCoverageTool ) ;
130+ logger . LogDebug ( Resources . CONV_DIAG_LocatingCodeCoverageToolSetupConfiguration ) ;
131+ ISetupConfiguration configurationQuery = setupConfigurationFactory . GetSetupConfigurationQuery ( ) ;
132+ if ( configurationQuery != null )
133+ {
134+ IEnumSetupInstances instanceEnumerator = configurationQuery . EnumInstances ( ) ;
135+
136+ int fetched ;
137+ ISetupInstance [ ] tempInstance = new ISetupInstance [ 1 ] ;
138+
139+ List < ISetupInstance2 > instances = new List < ISetupInstance2 > ( ) ;
140+ //Enumerate the configuration instances
141+ do
142+ {
143+ instanceEnumerator . Next ( 1 , tempInstance , out fetched ) ;
144+ if ( fetched > 0 )
145+ {
146+ ISetupInstance2 instance = ( ISetupInstance2 ) tempInstance [ 0 ] ;
147+ if ( instance . GetPackages ( ) . Any ( p => p . GetId ( ) == CodeCoverageInstallationPackage ) )
148+ {
149+ //Store instances that have code coverage package installed
150+ instances . Add ( ( ISetupInstance2 ) tempInstance [ 0 ] ) ;
151+ }
152+ }
153+ } while ( fetched > 0 ) ;
154+
155+ if ( instances . Count > 1 )
156+ {
157+ logger . LogDebug ( Resources . CONV_DIAG_MultipleVsVersionsInstalled , string . Join ( ", " , instances . Select ( i => i . GetInstallationVersion ( ) ) ) ) ;
158+ }
159+
160+ //Get the installation path for the latest visual studio found
161+ var visualStudioPath = instances . OrderByDescending ( i => i . GetInstallationVersion ( ) )
162+ . Select ( i => i . GetInstallationPath ( ) )
163+ . FirstOrDefault ( ) ;
164+
165+ if ( visualStudioPath != null )
166+ {
167+ toolPath = Path . Combine ( visualStudioPath , TeamToolPathandExeName ) ;
168+ }
169+ }
170+ else
171+ {
172+ logger . LogDebug ( Resources . CONV_DIAG_SetupConfigurationNotSupported ) ;
173+ }
174+
175+ return toolPath ;
176+ }
177+
178+ #endregion Code Coverage Tool path from setup configuration
179+
180+ #region Code Coverage Tool path from registry
181+
182+ private static string GetExeToolPathFromRegistry ( ILogger logger )
183+ {
184+ string toolPath = null ;
185+
186+ logger . LogDebug ( Resources . CONV_DIAG_LocatingCodeCoverageToolRegistry ) ;
102187 using ( RegistryKey key = Registry . LocalMachine . OpenSubKey ( VisualStudioRegistryPath , false ) )
103188 {
104189 // i.e. no VS installed
@@ -192,6 +277,8 @@ private static double TryGetVersionAsDouble(string versionKey)
192277 return result ;
193278 }
194279
280+ #endregion Code Coverage Tool path from registry
281+
195282 // was internal
196283 public static bool ConvertBinaryToXml ( string converterExeFilePath , string inputBinaryFilePath , string outputXmlFilePath , ILogger logger )
197284 {
0 commit comments