public void SolutionBindingSerializer_ReadSolutionBinding_NoFile()
        {
            // Setup
            SolutionBindingSerializer testSubject = this.CreateTestSubject();

            // Act (read)
            BoundSonarQubeProject read = testSubject.ReadSolutionBinding();

            // Verify
            Assert.IsNull(read, "Not expecting any binding information when there is no file");
            this.outputPane.AssertOutputStrings(0);
        }
        public void SolutionBindingSerializer_ReadSolutionBinding_NoFile()
        {
            // Arrange
            SolutionBindingSerializer testSubject = this.CreateTestSubject();

            // Act (read)
            BoundSonarQubeProject read = testSubject.ReadSolutionBinding();

            // Assert
            read.Should().BeNull("Not expecting any binding information when there is no file");
            this.outputPane.AssertOutputStrings(0);
        }
예제 #3
0
        public void CreateConnectionInformation_NoCredentials()
        {
            // Arrange
            var input = new BoundSonarQubeProject(new Uri("http://server"), "ProjectKey");

            // Act
            ConnectionInformation conn = input.CreateConnectionInformation();

            // Assert
            conn.ServerUri.Should().Be(input.ServerUri);
            conn.UserName.Should().BeNull();
            conn.Password.Should().BeNull();
        }
        public void CreateConnectionInformation_NoCredentials()
        {
            // Setup
            var input = new BoundSonarQubeProject(new Uri("http://server"), "ProjectKey");

            // Act
            ConnectionInformation conn = input.CreateConnectionInformation();

            // Verify
            Assert.AreEqual(input.ServerUri, conn.ServerUri);
            Assert.IsNull(conn.UserName);
            Assert.IsNull(conn.Password);
        }
        public void SolutionBindingSerializer_ReadSolutionBinding_OnClosedSolution()
        {
            // Arrange
            SolutionBindingSerializer testSubject = this.CreateTestSubject();

            this.dte.Solution = new SolutionMock(dte, "" /*When the solution is closed the file is empty*/);

            // Act (read)
            BoundSonarQubeProject read = testSubject.ReadSolutionBinding();

            // Assert
            read.Should().BeNull();
        }
예제 #6
0
        public void Equals_DifferentModes_AreNotEqual()
        {
            // Arrange
            var project1 = new BoundSonarQubeProject(new Uri("http://localhost"), "projectAAA", "projectName", organization: null);

            var standalone = BindingConfiguration.Standalone;
            var config1    = BindingConfiguration.CreateBoundConfiguration(project1, isLegacy: true);
            var config2    = BindingConfiguration.CreateBoundConfiguration(project1, isLegacy: false);

            // Act & Assert
            CheckAreNotEqual(config1, config2);
            CheckAreNotEqual(config2, config1);
        }
        public QualityProfile GetQualityProfile(BoundSonarQubeProject project, Language language)
        {
            // Block the call while the cache is being built.
            // If the task has already completed then this will return immediately (e.g. on subsequent calls)
            // If we time out waiting for the initial fetch then we return null.
            this.initialFetch?.Wait(MillisecondsToWaitForInitialFetch);

            QualityProfile profile;

            return(cachedQualityProfiles.TryGetValue(language, out profile)
                ? profile
                : null);
        }
        public BindingConfiguration Persist(BoundSonarQubeProject project, SonarLintMode bindingMode)
        {
            if (project == null)
            {
                throw new ArgumentNullException(nameof(project));
            }

            var writeSettings = GetWriteSettings(bindingMode);

            var success = writeSettings.HasValue &&
                          solutionBindingDataWriter.Write(writeSettings.Value.ConfigPath, project, writeSettings?.OnSuccessfulFileWrite);

            return(success ? CreateBindingConfiguration(writeSettings.Value.ConfigPath, project, bindingMode) : null);
        }
예제 #9
0
        public void CreateConnectionInformation_BasicAuthCredentials()
        {
            // Arrange
            var creds = new BasicAuthCredentials("UserName", "password".ToSecureString());
            var input = new BoundSonarQubeProject(new Uri("http://server"), "ProjectKey", creds);

            // Act
            ConnectionInformation conn = input.CreateConnectionInformation();

            // Assert
            conn.ServerUri.Should().Be(input.ServerUri);
            conn.UserName.Should().Be(creds.UserName);
            conn.Password.ToUnsecureString().Should().Be(creds.Password.ToUnsecureString());
        }
        private IEnumerable <Project> GetUnboundProjects(BoundSonarQubeProject binding)
        {
            if (binding == null)
            {
                return(Enumerable.Empty <Project>());
            }

            var projectSystem = this.serviceProvider.GetService <IProjectSystemHelper>();

            projectSystem.AssertLocalServiceIsNotNull();

            // Reuse the binding information passed in to avoid reading it more than once
            return(projectSystem.GetFilteredSolutionProjects().Except(this.GetBoundProjects(binding)));
        }
        public void CreateConnectionInformation_BasicAuthCredentials()
        {
            // Setup
            var creds = new BasicAuthCredentials("UserName", "password".ConvertToSecureString());
            var input = new BoundSonarQubeProject(new Uri("http://server"), "ProjectKey", creds);

            // Act
            ConnectionInformation conn = input.CreateConnectionInformation();

            // Verify
            Assert.AreEqual(input.ServerUri, conn.ServerUri);
            Assert.AreEqual(creds.UserName, conn.UserName);
            Assert.AreEqual(creds.Password.ConvertToUnsecureString(), conn.Password.ConvertToUnsecureString());
        }
        private void ConfigureValidSonarQubeServiceWrapper(BoundSonarQubeProject binding, DateTime timestamp,
                                                           string qualityProfileKey, params Language[] expectedLanguageProfiles)
        {
            var sqService = new Mock <ISonarQubeService>();

            this.host.SonarQubeService = sqService.Object;

            foreach (Language language in expectedLanguageProfiles)
            {
                sqService
                .Setup(x => x.GetQualityProfileAsync(binding.ProjectKey, null, language.ToServerLanguage(), It.IsAny <CancellationToken>()))
                .ReturnsAsync(new SonarQubeQualityProfile(qualityProfileKey, "", language.ToServerLanguage().Key, false, timestamp));
            }
        }
        private RuleSetInformation[] GetAggregatedSolutionRuleSets()
        {
            var solutionBinding = this.serviceProvider.GetService <ISolutionBindingSerializer>();

            solutionBinding.AssertLocalServiceIsNotNull();

            BoundSonarQubeProject bindingInfo = solutionBinding.ReadSolutionBinding();

            if (bindingInfo == null)
            {
                return(new RuleSetInformation[0]);
            }

            var projectSystem = this.serviceProvider.GetService <IProjectSystemHelper>();

            projectSystem.AssertLocalServiceIsNotNull();

            var ruleSetInfoProvider = this.serviceProvider.GetService <ISolutionRuleSetsInformationProvider>();

            ruleSetInfoProvider.AssertLocalServiceIsNotNull();

            var fileSystem = this.serviceProvider.GetService <IFileSystem>();

            fileSystem.AssertLocalServiceIsNotNull();

            var projectRuleSetAggregation = new Dictionary <string, RuleSetInformation>(StringComparer.OrdinalIgnoreCase);

            foreach (Project project in projectSystem.GetFilteredSolutionProjects())
            {
                string baselineRuleSet = ruleSetInfoProvider.CalculateSolutionSonarQubeRuleSetFilePath(
                    bindingInfo.ProjectKey,
                    Language.ForProject(project));

                if (!fileSystem.FileExist(baselineRuleSet))
                {
                    this.WriteWarning(Strings.ExpectedRuleSetNotFound, baselineRuleSet, project.FullName);
                    continue;
                }

                foreach (RuleSetDeclaration declaration in ruleSetInfoProvider.GetProjectRuleSetsDeclarations(project))
                {
                    string projectRuleSet = CalculateProjectRuleSetFullPath(ruleSetInfoProvider, project, declaration);

                    this.AddOrUpdateAggregatedRuleSetInformation(projectRuleSetAggregation, baselineRuleSet, declaration, projectRuleSet);
                }
            }

            return(projectRuleSetAggregation.Values.ToArray());
        }
예제 #14
0
        public void Equals_DifferentOrganisation_AreNotEqual()
        {
            // Arrange
            var project1 = new BoundSonarQubeProject(new Uri("http://localhost"), "projectAAA", "projectName",
                                                     organization: new SonarQubeOrganization("org1", "any"));
            var project2 = new BoundSonarQubeProject(new Uri("http://localhost"), "projectAAA", "projectName",
                                                     organization: new SonarQubeOrganization("ORG1", "any")); // different in case only

            var config1 = BindingConfiguration.CreateBoundConfiguration(project1, SonarLintMode.LegacyConnected);
            var config2 = BindingConfiguration.CreateBoundConfiguration(project2, SonarLintMode.LegacyConnected);

            // Act & Assert
            CheckAreNotEqual(config1, config2);
            CheckAreNotEqual(config2, config1);
        }
예제 #15
0
        private static BindingConfiguration CreateConfiguration(SonarLintMode mode, string serverUri)
        {
            if (mode == SonarLintMode.Standalone)
            {
                if (serverUri != null)
                {
                    Assert.Fail("Test setup error: should pass a null serverUri for standalone mode");
                }
                return(BindingConfiguration.Standalone);
            }

            var project = new BoundSonarQubeProject(new Uri(serverUri), "dummy.project.key", "dummy.projectName");

            return(BindingConfiguration.CreateBoundConfiguration(project, mode, "c:\\test"));
        }
예제 #16
0
        public void TestInitialize()
        {
            credentialsLoader         = new Mock <ISolutionBindingCredentialsLoader>();
            solutionBindingFileLoader = new Mock <ISolutionBindingFileLoader>();

            testSubject = new SolutionBindingDataReader(solutionBindingFileLoader.Object, credentialsLoader.Object);

            mockCredentials = new BasicAuthCredentials("user", "pwd".ToSecureString());

            boundSonarQubeProject = new BoundSonarQubeProject(
                new Uri("http://xxx.www.zzz/yyy:9000"),
                "MyProject Key",
                "projectName",
                mockCredentials);
        }
예제 #17
0
        public void Equals_DifferentServer_AreNotEqual()
        {
            // Arrange
            var project1 = new BoundSonarQubeProject(new Uri("http://localhost1"), "projectAAA", "projectName",
                                                     organization: new SonarQubeOrganization("org1", "any"));
            var project2 = new BoundSonarQubeProject(new Uri("http://localhost2"), "projectAAA", "projectName",
                                                     organization: new SonarQubeOrganization("org1", "any"));

            var config1 = BindingConfiguration.CreateBoundConfiguration(project1, isLegacy: true);
            var config2 = BindingConfiguration.CreateBoundConfiguration(project2, isLegacy: true);

            // Act & Assert
            CheckAreNotEqual(config1, config2);
            CheckAreNotEqual(config2, config1);
        }
        public void SolutionBindingSerializer_WriteSolutionBinding_ReadSolutionBinding_WithProfiles()
        {
            // Arrange
            SolutionBindingSerializer testSubject = this.CreateTestSubject();
            var serverUri  = new Uri("http://xxx.www.zzz/yyy:9000");
            var creds      = new BasicAuthCredentials("user", "pwd".ToSecureString());
            var projectKey = "MyProject Key";
            var written    = new BoundSonarQubeProject(serverUri, projectKey, "projectName", creds)
            {
                Profiles = new Dictionary <Language, ApplicableQualityProfile>()
                {
                    { Language.VBNET, new ApplicableQualityProfile {
                          ProfileKey = "VB"
                      } },
                    { Language.CSharp, new ApplicableQualityProfile {
                          ProfileKey = "CS", ProfileTimestamp = DateTime.Now
                      } }
                }
            };

            // Act (write)
            string output = testSubject.WriteSolutionBinding(written);

            this.sourceControlledFileSystem.WritePendingNoErrorsExpected();
            output.Should().NotBeNull("Expected a real file");
            this.TestContext.AddResultFile(output);
            File.Exists(output).Should().BeTrue("Expected a real file");

            // Assert
            this.store.data.Should().ContainKey(serverUri);

            // Act (read)
            BoundSonarQubeProject read = testSubject.ReadSolutionBinding();

            // Assert
            var newCreds = read.Credentials as BasicAuthCredentials;

            newCreds.Should().NotBe(creds, "Different credential instance were expected");
            newCreds.UserName.Should().Be(creds.UserName);
            newCreds.Password.ToUnsecureString().Should().Be(creds.Password.ToUnsecureString());
            read.ServerUri.Should().Be(written.ServerUri);
            (read.Profiles?.Count ?? 0).Should().Be(2);
            read.Profiles[Language.VBNET].ProfileKey.Should().Be(written.Profiles[Language.VBNET].ProfileKey);
            read.Profiles[Language.VBNET].ProfileTimestamp.Should().Be(written.Profiles[Language.VBNET].ProfileTimestamp);
            read.Profiles[Language.CSharp].ProfileKey.Should().Be(written.Profiles[Language.CSharp].ProfileKey);
            read.Profiles[Language.CSharp].ProfileTimestamp.Should().Be(written.Profiles[Language.CSharp].ProfileTimestamp);
            this.outputPane.AssertOutputStrings(0);
        }
예제 #19
0
        public void CreateConnectionInformation_NoCredentials()
        {
            // Arrange
            var input = new BoundSonarQubeProject(new Uri("http://server"), "ProjectKey", "projectName",
                                                  organization: new SonarQubeOrganization("org_key", "org_name"));

            // Act
            ConnectionInformation conn = input.CreateConnectionInformation();

            // Assert
            conn.ServerUri.Should().Be(input.ServerUri);
            conn.UserName.Should().BeNull();
            conn.Password.Should().BeNull();
            conn.Organization.Key.Should().Be("org_key");
            conn.Organization.Name.Should().Be("org_name");
        }
        // ISSUE : this method is doing too many things
        private RuleSetInformation[] CheckSlnLevelConfigExistsAndReturnAllProjectRuleSetsForAllConfigurations(
            BoundSonarQubeProject bindingInfo)
        {
            var projectSystem = this.serviceProvider.GetService <IProjectSystemHelper>();

            projectSystem.AssertLocalServiceIsNotNull();

            var ruleSetInfoProvider = this.serviceProvider.GetService <ISolutionRuleSetsInformationProvider>();

            ruleSetInfoProvider.AssertLocalServiceIsNotNull();

            var fileSystem = this.serviceProvider.GetService <IFileSystem>();

            fileSystem.AssertLocalServiceIsNotNull();

            var projectRuleSetAggregation = new Dictionary <string, RuleSetInformation>(StringComparer.OrdinalIgnoreCase);

            foreach (Project project in projectSystem.GetFilteredSolutionProjects())
            {
                // Solution-level checks (done here because the expected solution-level config
                // depends on the languages supported by the project that exist)
                string baselineRuleSet = ruleSetInfoProvider.CalculateSolutionSonarQubeRuleSetFilePath(
                    bindingInfo.ProjectKey,
                    ProjectToLanguageMapper.GetLanguageForProject(project),
                    SonarLintMode.LegacyConnected);

                if (!fileSystem.FileExist(baselineRuleSet))
                {
                    this.WriteWarning(Strings.ExpectedRuleSetNotFound, baselineRuleSet, project.FullName);
                    continue;
                }

                if (!BindingRefactoringDumpingGround.IsProjectLevelBindingRequired(project))
                {
                    continue;
                }

                foreach (RuleSetDeclaration declaration in ruleSetInfoProvider.GetProjectRuleSetsDeclarations(project))
                {
                    string projectRuleSet = CalculateProjectRuleSetFullPath(ruleSetInfoProvider, project, declaration);

                    this.AddOrUpdateAggregatedRuleSetInformation(projectRuleSetAggregation, baselineRuleSet, declaration, projectRuleSet);
                }
            }

            return(projectRuleSetAggregation.Values.ToArray());
        }
        public void BoundProject_Serialization()
        {
            // Arrange
            var serverUri   = new Uri("https://finding-nemo.org");
            var projectKey  = "MyProject Key";
            var testSubject = new BoundSonarQubeProject(serverUri, projectKey, "projectName", new BasicAuthCredentials("used", "pwd".ToSecureString()));

            // Act (serialize + de-serialize)
            string data = JsonHelper.Serialize(testSubject);
            BoundSonarQubeProject deserialized = JsonHelper.Deserialize <BoundSonarQubeProject>(data);

            // Assert
            deserialized.Should().NotBe(testSubject);
            deserialized.ProjectKey.Should().Be(testSubject.ProjectKey);
            deserialized.ServerUri.Should().Be(testSubject.ServerUri);
            deserialized.Credentials.Should().BeNull();
        }
예제 #22
0
            QualityProfile IQualityProfileProvider.GetQualityProfile(BoundSonarQubeProject project, Language language)
            {
                GetQualityProfileCallCount++;

                if (!initialFetchStarted)
                {
                    initialFetchStarted = true;

                    // Mark that the initial fetch has started
                    InitialFetchStartedWaitHandle.Set();
                }

                QualityProfile profile;

                ProfilesToReturnByLanguage.TryGetValue(language, out profile);
                return(profile);
            }
        public void Equals_DifferentProjects_AreNotEqual()
        {
            // Arrange
            var project1 = new BoundSonarQubeProject(new Uri("http://localhost"), "projectAAA", "projectName", organization: null);
            var project2 = new BoundSonarQubeProject(new Uri("http://localhost"), "projectBBB", "projectName", organization: null);

            var standalone = BindingConfiguration.Standalone;
            var config1    = BindingConfiguration.CreateBoundConfiguration(project1, SonarLintMode.LegacyConnected, "c:\\");
            var config2    = BindingConfiguration.CreateBoundConfiguration(project2, SonarLintMode.LegacyConnected, "c:\\");

            // Act & Assert
            CheckAreNotEqual(config1, config2);
            CheckAreNotEqual(config2, config1);

            CheckAreNotEqual(standalone, config1);
            CheckAreNotEqual(config1, standalone);
        }
예제 #24
0
        public void BoundSonarQubeProject_Serialization()
        {
            // Setup
            var serverUri   = new Uri("https://finding-nemo.org");
            var projectKey  = "MyProject Key";
            var testSubject = new BoundSonarQubeProject(serverUri, projectKey, new BasicAuthCredentials("used", "pwd".ConvertToSecureString()));

            // Act (serialize + de-serialize)
            string data = JsonHelper.Serialize(testSubject);
            BoundSonarQubeProject deserialized = JsonHelper.Deserialize <BoundSonarQubeProject>(data);

            // Verify
            Assert.AreNotSame(testSubject, deserialized);
            Assert.AreEqual(testSubject.ProjectKey, deserialized.ProjectKey);
            Assert.AreEqual(testSubject.ServerUri, deserialized.ServerUri);
            Assert.IsNull(deserialized.Credentials);
        }
        public void WriteSolution_WriteThrowsCriticalException_NotSuppressed()
        {
            // Arrange
            SetSolutionFilePath(@"c:\mysolutionfile.foo");
            fileMock.Setup(x => x.WriteAllText(It.IsAny <string>(), It.IsAny <string>())).Throws <StackOverflowException>();

            var boundProject = new BoundSonarQubeProject
            {
                ProjectKey = "mykey",
                ServerUri  = new Uri("http://localhost:9000"),
            };

            Action act = () => testSubject.WriteSolutionBinding(boundProject);

            // Act & Assert
            act.ShouldThrow <StackOverflowException>();
        }
        public void SolutionBindingSerializer_WriteSolutionBinding_ReadSolutionBinding_WithProfiles()
        {
            // Setup
            SolutionBindingSerializer testSubject = this.CreateTestSubject();
            var serverUri  = new Uri("http://xxx.www.zzz/yyy:9000");
            var creds      = new BasicAuthCredentials("user", "pwd".ConvertToSecureString());
            var projectKey = "MyProject Key";
            var written    = new BoundSonarQubeProject(serverUri, projectKey, creds);

            written.Profiles = new Dictionary <Language, ApplicableQualityProfile>();
            written.Profiles[Language.VBNET] = new ApplicableQualityProfile {
                ProfileKey = "VB"
            };
            written.Profiles[Language.CSharp] = new ApplicableQualityProfile {
                ProfileKey = "CS", ProfileTimestamp = DateTime.Now
            };

            // Act (write)
            string output = testSubject.WriteSolutionBinding(written);

            this.sourceControlledFileSystem.WritePendingNoErrorsExpected();
            Assert.IsNotNull(output, "Expected a real file");
            this.TestContext.AddResultFile(output);
            Assert.IsTrue(File.Exists(output), "Expected a real file");

            // Verify
            this.store.AssertHasCredentials(serverUri);

            // Act (read)
            BoundSonarQubeProject read = testSubject.ReadSolutionBinding();

            // Verify
            var newCreds = read.Credentials as BasicAuthCredentials;

            Assert.AreNotEqual(creds, newCreds, "Different credential instance were expected");
            Assert.AreEqual(creds.UserName, newCreds.UserName);
            Assert.AreEqual(creds.Password.ConvertToUnsecureString(), newCreds.Password.ConvertToUnsecureString());
            Assert.AreEqual(written.ServerUri, read.ServerUri);
            Assert.AreEqual(2, read.Profiles?.Count ?? 0);
            Assert.AreEqual(written.Profiles[Language.VBNET].ProfileKey, read.Profiles[Language.VBNET].ProfileKey);
            Assert.AreEqual(written.Profiles[Language.VBNET].ProfileTimestamp, read.Profiles[Language.VBNET].ProfileTimestamp);
            Assert.AreEqual(written.Profiles[Language.CSharp].ProfileKey, read.Profiles[Language.CSharp].ProfileKey);
            Assert.AreEqual(written.Profiles[Language.CSharp].ProfileTimestamp, read.Profiles[Language.CSharp].ProfileTimestamp);
            this.outputPane.AssertOutputStrings(0);
        }
예제 #27
0
        public void GetConfig_LegacyConfigOnly_ReturnsLegacy()
        {
            // Arrange
            legacyPathProvider.Setup(x => x.Get()).Returns("old");

            var expectedProject = new BoundSonarQubeProject();

            solutionBindingSerializer.Setup(x => x.Read("old")).Returns(expectedProject);

            // Act
            var actual = testSubject.GetConfiguration();

            // Assert
            actual.Should().NotBeNull();
            actual.Project.Should().NotBeNull();
            actual.Project.Should().BeSameAs(expectedProject);
            actual.Mode.Should().Be(SonarLintMode.LegacyConnected);
        }
예제 #28
0
        private void ApplyBindingInformation(BoundSonarQubeProject bound)
        {
            // Set the project key that should become bound once the connection workflow has completed
            this.VisualStateManager.BoundProjectKey = bound.ProjectKey;

            // Recreate the connection information from what was persisted
            ConnectionInformation connectionInformation = bound.CreateConnectionInformation();

            Debug.Assert(this.ActiveSection != null, "Expected ActiveSection to be set");
            Debug.Assert(this.ActiveSection?.RefreshCommand != null, "Refresh command is not set");
            // Run the refresh workflow, passing the connection information
            var refreshCmd = this.ActiveSection.RefreshCommand;

            if (refreshCmd.CanExecute(connectionInformation))
            {
                refreshCmd.Execute(connectionInformation); // start the workflow
            }
        }
            private bool IsUpdateRequired(BoundSonarQubeProject binding, IEnumerable <Language> projectLanguages,
                                          CancellationToken token)
            {
                Debug.Assert(binding != null);

                IDictionary <Language, SonarQubeQualityProfile> newProfiles = null;

                try
                {
                    newProfiles = TryGetLatestProfilesAsync(binding, projectLanguages, token).GetAwaiter().GetResult();
                }
                catch (Exception)
                {
                    this.host.Logger.WriteLine(Strings.SonarLintProfileCheckFailed);
                    return(false); // Error, can't proceed
                }

                if (!newProfiles.Keys.All(binding.Profiles.ContainsKey))
                {
                    this.host.Logger.WriteLine(Strings.SonarLintProfileCheckSolutionRequiresMoreProfiles);
                    return(true); // Missing profile, refresh
                }

                foreach (var keyValue in binding.Profiles)
                {
                    Language language = keyValue.Key;
                    ApplicableQualityProfile oldProfileInfo = keyValue.Value;

                    if (!newProfiles.ContainsKey(language))
                    {
                        // Not a relevant profile, we should just ignore it.
                        continue;
                    }

                    SonarQubeQualityProfile newProfileInfo = newProfiles[language];
                    if (this.HasProfileChanged(newProfileInfo, oldProfileInfo))
                    {
                        return(true);
                    }
                }

                this.host.Logger.WriteLine(Strings.SonarLintProfileCheckQualityProfileIsUpToDate);
                return(false); // Up-to-date
            }
예제 #30
0
        public void GetConfig_NoLegacyProjectAtFileLocation_ConnectedProjectAtFileLocation_ReturnsConnected()
        {
            // Arrange
            legacyPathProvider.Setup(x => x.Get()).Returns("legacy");
            solutionBindingSerializer.Setup(x => x.Read("legacy")).Returns(null as BoundSonarQubeProject);

            var expectedProject = new BoundSonarQubeProject();

            newPathProvider.Setup(x => x.Get()).Returns("new");
            solutionBindingSerializer.Setup(x => x.Read("new")).Returns(expectedProject);

            // Act
            var actual = testSubject.GetConfiguration();

            // Assert
            actual.Should().NotBeNull();
            actual.Project.Should().BeSameAs(expectedProject);
            actual.Mode.Should().Be(SonarLintMode.Connected);
        }