public void AnalysisConfGen_Simple()
        {
            // Arrange
            string analysisDir = TestUtils.CreateTestSpecificFolder(this.TestContext);

            TestLogger logger = new TestLogger();

            ListPropertiesProvider propertyProvider = new ListPropertiesProvider();
            propertyProvider.AddProperty(SonarProperties.HostUrl, "http://foo");
            ProcessedArgs args = new ProcessedArgs("valid.key", "valid.name", "1.0", false, EmptyPropertyProvider.Instance, propertyProvider);

            TeamBuildSettings tbSettings = TeamBuildSettings.CreateNonTeamBuildSettingsForTesting(analysisDir);

            Dictionary<string, string> serverSettings = new Dictionary<string, string>();
            serverSettings.Add("server.key.1", "server.value.1");

            AnalyzerSettings analyzerSettings = new AnalyzerSettings();
            analyzerSettings.RuleSetFilePath = "c:\\xxx.ruleset";
            analyzerSettings.AdditionalFilePaths = new List<string>();
            analyzerSettings.AdditionalFilePaths.Add("f:\\additionalPath1.txt");
            analyzerSettings.AnalyzerAssemblyPaths = new List<string>();
            analyzerSettings.AnalyzerAssemblyPaths.Add("f:\\temp\\analyzer1.dll");

            Directory.CreateDirectory(tbSettings.SonarConfigDirectory); // config directory needs to exist

            // Act
            AnalysisConfig actualConfig = AnalysisConfigGenerator.GenerateFile(args, tbSettings, serverSettings, analyzerSettings, logger);

            // Assert
            AssertConfigFileExists(actualConfig);
            logger.AssertErrorsLogged(0);
            logger.AssertWarningsLogged(0);

            Assert.AreEqual("valid.key", actualConfig.SonarProjectKey);
            Assert.AreEqual("valid.name", actualConfig.SonarProjectName);
            Assert.AreEqual("1.0", actualConfig.SonarProjectVersion);

            Assert.AreEqual("http://foo", actualConfig.SonarQubeHostUrl);

            Assert.AreEqual(tbSettings.SonarBinDirectory, actualConfig.SonarBinDir);
            Assert.AreEqual(tbSettings.SonarConfigDirectory, actualConfig.SonarConfigDir);
            Assert.AreEqual(tbSettings.SonarOutputDirectory, actualConfig.SonarOutputDir);
            Assert.AreEqual(tbSettings.SonarRunnerWorkingDirectory, actualConfig.SonarRunnerWorkingDirectory);
            Assert.AreEqual(tbSettings.BuildUri, actualConfig.GetBuildUri());
            Assert.AreEqual(tbSettings.TfsUri, actualConfig.GetTfsUri());

            Assert.IsNotNull(actualConfig.ServerSettings);
            Property serverProperty = actualConfig.ServerSettings.SingleOrDefault(s => string.Equals(s.Id, "server.key.1", System.StringComparison.Ordinal));
            Assert.IsNotNull(serverProperty);
            Assert.AreEqual("server.value.1", serverProperty.Value);

            Assert.AreSame(analyzerSettings, actualConfig.AnalyzerSettings);
        }
        private bool FetchArgumentsAndRulesets(ProcessedArgs args, TeamBuildSettings settings, out IDictionary<string, string> serverSettings, out AnalyzerSettings analyzerSettings)
        {
            string hostUrl = args.GetSetting(SonarProperties.HostUrl);
            serverSettings = null;
            analyzerSettings = null;

            ISonarQubeServer server = this.factory.CreateSonarQubeServer(args, this.logger);
            try
            {
                this.logger.LogInfo(Resources.MSG_FetchingAnalysisConfiguration);

                // Respect sonar.branch setting if set
                string projectBranch = null;
                args.TryGetSetting(SonarProperties.ProjectBranch, out projectBranch);

                // Fetch the SonarQube project properties
                serverSettings = server.GetProperties(args.ProjectKey, projectBranch);

                // Generate the FxCop rulesets
                this.logger.LogInfo(Resources.MSG_GeneratingRulesets);
                GenerateFxCopRuleset(server, args.ProjectKey, projectBranch,
                    "csharp", "cs", "fxcop", Path.Combine(settings.SonarConfigDirectory, FxCopCSharpRuleset));
                GenerateFxCopRuleset(server, args.ProjectKey, projectBranch,
                    "vbnet", "vbnet", "fxcop-vbnet", Path.Combine(settings.SonarConfigDirectory, FxCopVBNetRuleset));

                IAnalyzerProvider analyzerProvider = this.factory.CreateAnalyzerProvider(this.logger);
                Debug.Assert(analyzerProvider != null, "Factory should not return null");

                analyzerSettings = analyzerProvider.SetupAnalyzers(server, settings, args.ProjectKey, projectBranch);
            }
            catch (WebException ex)
            {
                if (Utilities.HandleHostUrlWebException(ex, hostUrl, this.logger))
                {
                    return false;
                }

                throw;
            }
            finally
            {
                Utilities.SafeDispose(server);
            }

            return true;
        }
        /// <summary>
        /// Combines the various configuration options into the AnalysisConfig file
        /// used by the build and post-processor. Saves the file and returns the config instance.
        /// </summary>
        /// <returns></returns>
        public static AnalysisConfig GenerateFile(ProcessedArgs args,
            TeamBuildSettings settings,
            IDictionary<string, string> serverProperties, 
            AnalyzerSettings analyzerSettings, // could be null if the Rolsyn profile couldn't be retrieved
            ILogger logger)
        {
            if (args == null)
            {
                throw new ArgumentNullException("args");
            }
            if (settings == null)
            {
                throw new ArgumentNullException("settings");
            }
            if (serverProperties == null)
            {
                throw new ArgumentNullException("serverProperties");
            }
            if (logger == null)
            {
                throw new ArgumentNullException("logger");
            }

            AnalysisConfig config = new AnalysisConfig();
            config.SonarProjectKey = args.ProjectKey;
            config.SonarProjectName = args.ProjectName;
            config.SonarProjectVersion = args.ProjectVersion;
            config.SonarQubeHostUrl = args.GetSetting(SonarProperties.HostUrl);

            config.SetBuildUri(settings.BuildUri);
            config.SetTfsUri(settings.TfsUri);
            config.SonarConfigDir = settings.SonarConfigDirectory;
            config.SonarOutputDir = settings.SonarOutputDirectory;
            config.SonarBinDir = settings.SonarBinDirectory;
            config.SonarRunnerWorkingDirectory = settings.SonarRunnerWorkingDirectory;

            // Add the server properties to the config
            config.ServerSettings = new AnalysisProperties();

            foreach (var property in serverProperties)
            {
                if (!IsSecuredServerProperty(property.Key))
                {
                    AddSetting(config.ServerSettings, property.Key, property.Value);
                }
            }

            // Add command line arguments
            config.LocalSettings = new AnalysisProperties();
            foreach (var property in args.LocalProperties.GetAllProperties())
            {
                AddSetting(config.LocalSettings, property.Id, property.Value);
            }

            // Set the pointer to the properties file
            if (args.PropertiesFileName != null)
            {
                config.SetSettingsFilePath(args.PropertiesFileName);
            }

            config.AnalyzerSettings = analyzerSettings;

            config.Save(settings.AnalysisConfigFilePath);

            return config;
        }
 private static void CheckExpectedAssemblies(AnalyzerSettings actualSettings, params string[] expected)
 {
     foreach(string expectedItem in expected)
     {
         Assert.IsTrue(actualSettings.AnalyzerAssemblyPaths.Contains(expectedItem, StringComparer.OrdinalIgnoreCase),
             "Expected assembly file path was not returned: {0}", expectedItem);
     }
     Assert.AreEqual(expected.Length, actualSettings.AnalyzerAssemblyPaths.Count(), "Too many assembly file paths returned");
 }
        private static void AssertAnalyzerSetupNotPerformed(AnalyzerSettings actualSettings, string rootTestDir)
        {
            Assert.IsNull(actualSettings, "Not expecting a config instance to have been returned");

            string filePath = GetExpectedRulesetFilePath(rootTestDir);
            Assert.IsFalse(File.Exists(filePath), "Not expecting the ruleset file to exist: {0}", filePath);
        }
        private void CheckExpectedAdditionalFileExists(string expectedFileName, string expectedContent, AnalyzerSettings actualSettings)
        {
            // Check one file of the expected name exists
            IEnumerable<string> matches = actualSettings.AdditionalFilePaths.Where(actual => string.Equals(expectedFileName, Path.GetFileName(actual), System.StringComparison.OrdinalIgnoreCase));
            Assert.AreEqual(1, matches.Count(), "Unexpected number of files named \"{0}\". One and only one expected", expectedFileName);

            // Check the file exists and has the expected content
            string actualFilePath = matches.First();
            Assert.IsTrue(File.Exists(actualFilePath), "AdditionalFile does not exist: {0}", actualFilePath);

            // Dump the contents to help with debugging
            this.TestContext.AddResultFile(actualFilePath);
            this.TestContext.WriteLine("File contents: {0}", actualFilePath);
            this.TestContext.WriteLine(File.ReadAllText(actualFilePath));
            this.TestContext.WriteLine("");

            if (expectedContent != null) // null expected means "don't check"
            {
                Assert.AreEqual(expectedContent, File.ReadAllText(actualFilePath), "Additional file does not have the expected content: {0}", expectedFileName);
            }
        }
 private void CheckExpectedAdditionalFiles(WellKnownProfile expected, AnalyzerSettings actualSettings)
 {
     foreach (string expectedFileName in expected.AdditionalFiles.Keys)
     {
         string expectedContent = expected.AdditionalFiles[expectedFileName];
         CheckExpectedAdditionalFileExists(expectedFileName, expectedContent, actualSettings);
     }
 }
        private void CheckRuleset(AnalyzerSettings actualSettings, string rootTestDir)
        {
            Assert.IsFalse(string.IsNullOrWhiteSpace(actualSettings.RuleSetFilePath), "Ruleset file path should be set");
            Assert.IsTrue(Path.IsPathRooted(actualSettings.RuleSetFilePath), "Ruleset file path should be absolute");
            Assert.IsTrue(File.Exists(actualSettings.RuleSetFilePath), "Specified ruleset file does not exist: {0}", actualSettings.RuleSetFilePath);
            this.TestContext.AddResultFile(actualSettings.RuleSetFilePath);

            CheckFileIsXml(actualSettings.RuleSetFilePath);

            Assert.AreEqual(RoslynAnalyzerProvider.RoslynCSharpRulesetFileName, Path.GetFileName(actualSettings.RuleSetFilePath), "Ruleset file does not have the expected name");

            string expectedFilePath = GetExpectedRulesetFilePath(rootTestDir);
            Assert.AreEqual(expectedFilePath, actualSettings.RuleSetFilePath, "Ruleset was not written to the expected location");

        }
        private static void CheckSettingsInvariants(AnalyzerSettings actualSettings)
        {
            Assert.IsNotNull(actualSettings, "Not expecting the config to be null");
            Assert.IsNotNull(actualSettings.AdditionalFilePaths);
            Assert.IsNotNull(actualSettings.AnalyzerAssemblyPaths);
            Assert.IsFalse(string.IsNullOrEmpty(actualSettings.RuleSetFilePath));

            // Any file paths returned in the config should exist
            foreach (string filePath in actualSettings.AdditionalFilePaths)
            {
                Assert.IsTrue(File.Exists(filePath), "Expected additional file does not exist: {0}", filePath);
            }
            Assert.IsTrue(File.Exists(actualSettings.RuleSetFilePath), "Specified ruleset does not exist: {0}", actualSettings.RuleSetFilePath);
        }
        private AnalyzerSettings ProcessProfile(RoslynExportProfile profile)
        {
            Debug.Assert(profile != null, "Expecting a valid profile");

            string rulesetFilePath = this.UnpackRuleset(profile);
            if (rulesetFilePath == null)
            {
                return null;
            }

            IEnumerable<string> additionalFiles = this.UnpackAdditionalFiles(profile);

            IEnumerable<string> analyzersAssemblies = this.FetchAnalyzerAssemblies(profile);

            AnalyzerSettings compilerConfig = new AnalyzerSettings(rulesetFilePath,
                analyzersAssemblies ?? Enumerable.Empty<string>(),
                additionalFiles ?? Enumerable.Empty<string>());
            return compilerConfig;
        }
        /// <summary>
        /// Combines the various configuration options into the AnalysisConfig file
        /// used by the build and post-processor. Saves the file and returns the config instance.
        /// </summary>
        /// <param name="args">Processed command line arguments supplied the user</param>
        /// <param name="buildSettings">Build environment settings</param>
        /// <param name="serverProperties">Analysis properties downloaded from the SonarQube server</param>
        /// <param name="analyzerSettings">Specifies the Roslyn analyzers to use</param>
        /// <param name="programmaticProperties">Any additional programmatically set analysis properties. Any user-specified values will take priority</param>
        public static AnalysisConfig GenerateFile(ProcessedArgs args,
            TeamBuildSettings buildSettings,
            IDictionary<string, string> serverProperties,
            AnalyzerSettings analyzerSettings,
            AnalysisProperties programmaticProperties,
            ILogger logger)
        {
            if (args == null)
            {
                throw new ArgumentNullException("args");
            }
            if (buildSettings == null)
            {
                throw new ArgumentNullException("settings");
            }
            if (serverProperties == null)
            {
                throw new ArgumentNullException("serverProperties");
            }
            if (analyzerSettings == null)
            {
                throw new ArgumentNullException("analyzerSettings");
            }
            if (programmaticProperties == null)
            {
                throw new ArgumentNullException("programmaticProperties");
            }
            if (logger == null)
            {
                throw new ArgumentNullException("logger");
            }

            AnalysisConfig config = new AnalysisConfig();
            config.SonarProjectKey = args.ProjectKey;
            config.SonarProjectName = args.ProjectName;
            config.SonarProjectVersion = args.ProjectVersion;
            config.SonarQubeHostUrl = args.GetSetting(SonarProperties.HostUrl);

            config.SetBuildUri(buildSettings.BuildUri);
            config.SetTfsUri(buildSettings.TfsUri);

            config.SonarConfigDir = buildSettings.SonarConfigDirectory;
            config.SonarOutputDir = buildSettings.SonarOutputDirectory;
            config.SonarBinDir = buildSettings.SonarBinDirectory;
            config.SonarRunnerWorkingDirectory = buildSettings.SonarRunnerWorkingDirectory;
            config.SourcesDirectory = buildSettings.SourcesDirectory;

            // Add the server properties to the config
            config.ServerSettings = new AnalysisProperties();

            foreach (var property in serverProperties)
            {
                if (!IsSecuredServerProperty(property.Key))
                {
                    AddSetting(config.ServerSettings, property.Key, property.Value);
                }
            }

            // Add command line arguments and programmatic properties.
            // Command line arguments take precedence
            AggregatePropertiesProvider aggProvider = new AggregatePropertiesProvider(args.LocalProperties, new ListPropertiesProvider(programmaticProperties));

            config.LocalSettings = new AnalysisProperties();
            foreach (var property in aggProvider.GetAllProperties())
            {
                AddSetting(config.LocalSettings, property.Id, property.Value);
            }

            // Set the pointer to the properties file
            if (args.PropertiesFileName != null)
            {
                config.SetSettingsFilePath(args.PropertiesFileName);
            }

            config.AnalyzerSettings = analyzerSettings;

            config.Save(buildSettings.AnalysisConfigFilePath);

            return config;
        }
        private static void AssertAnalyzerSetupNotPerformed(AnalyzerSettings actualSettings, string rootTestDir)
        {
            Assert.IsNotNull(actualSettings, "Not expecting the settings to be null");

            string filePath = GetExpectedRulesetFilePath(rootTestDir);
            Assert.IsFalse(File.Exists(filePath), "Not expecting the ruleset file to exist: {0}", filePath);
        }
        public void AnalysisConfGen_CommandLineAndProgrammaticProperties()
        {
            // Arrange
            TestLogger logger = new TestLogger();

            string analysisDir = TestUtils.CreateTestSpecificFolder(this.TestContext);
            TeamBuildSettings tbSettings = TeamBuildSettings.CreateNonTeamBuildSettingsForTesting(analysisDir);

            Dictionary<string, string> emptyServerProperties = new Dictionary<string, string>();
            AnalyzerSettings emptyAnalyzerSettings = new AnalyzerSettings();
            Directory.CreateDirectory(tbSettings.SonarConfigDirectory); // config directory needs to exist

            // Define a set of user properties
            ListPropertiesProvider userProperties = new ListPropertiesProvider();
            userProperties.AddProperty("sonar.host.url", "http://host"); // required
            userProperties.AddProperty("user1", "user value 1");
            userProperties.AddProperty("shared.key.1", "user value for shared.key.1");
            ProcessedArgs cmdLineArgs = new ProcessedArgs("key", "name", "version", false, userProperties, EmptyPropertyProvider.Instance);

            // Define a set of programmatic properties
            AnalysisProperties programmaticProperties = new AnalysisProperties();
            programmaticProperties.Add(new Property() { Id = "prog1", Value = "prog value 1" });
            programmaticProperties.Add(new Property() { Id = "shared.key.1", Value = "prog value for shared.key.1" });

            // Act
            AnalysisConfig actualConfig = AnalysisConfigGenerator.GenerateFile(cmdLineArgs, tbSettings, emptyServerProperties, emptyAnalyzerSettings, programmaticProperties, logger);

            // Assert
            AssertConfigFileExists(actualConfig);
            logger.AssertErrorsLogged(0);
            logger.AssertWarningsLogged(0);

            // Check that user properties take precedence over the programmatic ones
            AssertExpectedLocalSetting("sonar.host.url", "http://host", actualConfig);
            AssertExpectedLocalSetting("user1", "user value 1", actualConfig);
            AssertExpectedLocalSetting("shared.key.1", "user value for shared.key.1", actualConfig);
            AssertExpectedLocalSetting("prog1", "prog value 1", actualConfig);
        }