From 6c17e001619e865f99751298fbce3bac0c40b137 Mon Sep 17 00:00:00 2001 From: Gabriela Trutan Date: Mon, 7 Oct 2024 11:27:02 +0200 Subject: [PATCH 1/4] SLVS-1479 Introduce class to encapsulate showing the ManageBindingDialog. This has multiple advantages including better testability of code and the fact that the callers don't have to add references to all the services required to show the ManageBinding dialog, --- .../UI/ConnectedModeManagerTests.cs | 41 ++++++++++++++ src/ConnectedMode/UI/ConnectedModeManager.cs | 53 +++++++++++++++++++ 2 files changed, 94 insertions(+) create mode 100644 src/ConnectedMode.UnitTests/UI/ConnectedModeManagerTests.cs create mode 100644 src/ConnectedMode/UI/ConnectedModeManager.cs diff --git a/src/ConnectedMode.UnitTests/UI/ConnectedModeManagerTests.cs b/src/ConnectedMode.UnitTests/UI/ConnectedModeManagerTests.cs new file mode 100644 index 0000000000..2a1ad4ff42 --- /dev/null +++ b/src/ConnectedMode.UnitTests/UI/ConnectedModeManagerTests.cs @@ -0,0 +1,41 @@ +/* + * SonarLint for Visual Studio + * Copyright (C) 2016-2024 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 SonarLint.VisualStudio.ConnectedMode.UI; +using SonarLint.VisualStudio.TestInfrastructure; + +namespace SonarLint.VisualStudio.ConnectedMode.UnitTests.UI +{ + [TestClass] + public class ConnectedModeManagerTests + { + [TestMethod] + public void MefCtor_CheckIsExported() + { + MefTestHelpers.CheckTypeCanBeImported( + MefTestHelpers.CreateExport(), + MefTestHelpers.CreateExport()); + } + + [TestMethod] + public void MefCtor_CheckIsSingleton() + => MefTestHelpers.CheckIsNonSharedMefComponent(); + } +} diff --git a/src/ConnectedMode/UI/ConnectedModeManager.cs b/src/ConnectedMode/UI/ConnectedModeManager.cs new file mode 100644 index 0000000000..026ae6cbe0 --- /dev/null +++ b/src/ConnectedMode/UI/ConnectedModeManager.cs @@ -0,0 +1,53 @@ +/* + * SonarLint for Visual Studio + * Copyright (C) 2016-2024 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.ComponentModel.Composition; +using System.Diagnostics.CodeAnalysis; +using System.Windows; +using SonarLint.VisualStudio.ConnectedMode.UI.ManageBinding; + +namespace SonarLint.VisualStudio.ConnectedMode.UI; + +public interface IConnectedModeManager +{ + void ShowManageBindingDialog(bool useSharedBindingOnInitialization = false); +} + +[Export(typeof(IConnectedModeManager))] +[PartCreationPolicy(CreationPolicy.NonShared)] +internal sealed class ConnectedModeManager : IConnectedModeManager +{ + private readonly IConnectedModeServices connectedModeServices; + private readonly IConnectedModeBindingServices connectedModeBindingServices; + + [ImportingConstructor] + public ConnectedModeManager(IConnectedModeServices connectedModeServices, IConnectedModeBindingServices connectedModeBindingServices) + { + this.connectedModeServices = connectedModeServices; + this.connectedModeBindingServices = connectedModeBindingServices; + } + + [ExcludeFromCodeCoverage] // UI, not really unit-testable + public void ShowManageBindingDialog(bool useSharedBindingOnInitialization = false) + { + var manageBindingDialog = new ManageBindingDialog(connectedModeServices, connectedModeBindingServices, useSharedBindingOnInitialization); + manageBindingDialog.ShowDialog(Application.Current.MainWindow); + } +} From 9ade4c70367bfba376cc4d3709a971b0d6f27492 Mon Sep 17 00:00:00 2001 From: Gabriela Trutan Date: Mon, 7 Oct 2024 11:39:03 +0200 Subject: [PATCH 2/4] SLVS-1479 Show the ManageBinding dialog when infobar regarding the connection to the server is shown. --- .../Binding/BindingSuggestionHandlerTests.cs | 18 +++++++++--------- .../Binding/BindingSuggestionHandler.cs | 10 +++++----- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/Integration.UnitTests/Binding/BindingSuggestionHandlerTests.cs b/src/Integration.UnitTests/Binding/BindingSuggestionHandlerTests.cs index ad5dca437a..5ba5c834f6 100644 --- a/src/Integration.UnitTests/Binding/BindingSuggestionHandlerTests.cs +++ b/src/Integration.UnitTests/Binding/BindingSuggestionHandlerTests.cs @@ -19,11 +19,11 @@ */ using SonarLint.VisualStudio.ConnectedMode.Binding.Suggestion; +using SonarLint.VisualStudio.ConnectedMode.UI; using SonarLint.VisualStudio.Core.Notifications; using SonarLint.VisualStudio.Core; using SonarLint.VisualStudio.TestInfrastructure; using SonarLint.VisualStudio.Core.Binding; -using SonarLint.VisualStudio.Integration.TeamExplorer; using SonarLint.VisualStudio.Integration.Binding; namespace SonarLint.VisualStudio.Integration.UnitTests.Binding; @@ -38,7 +38,7 @@ public void MefCtor_CheckExports() MefTestHelpers.CreateExport(), MefTestHelpers.CreateExport(), MefTestHelpers.CreateExport(), - MefTestHelpers.CreateExport(), + MefTestHelpers.CreateExport(), MefTestHelpers.CreateExport()); } @@ -89,17 +89,17 @@ public void Notify_WithBoundProject_ShowsConflictMessage() public void Notify_ConnectAction_OpensSonarQubePage() { var notificationService = Substitute.For(); - var teamExplorerController = Substitute.For(); + var connectedModeManager = Substitute.For(); - var testSubject = CreateTestSubject(sonarLintMode: SonarLintMode.Standalone, notificationService: notificationService, teamExplorerController: teamExplorerController); + var testSubject = CreateTestSubject(sonarLintMode: SonarLintMode.Standalone, notificationService: notificationService, connectedModeManager: connectedModeManager); testSubject.Notify(); var notification = (Notification)notificationService.ReceivedCalls().Single().GetArguments().Single(); var connectAction = notification.Actions.First(x => x.CommandText.Equals(BindingStrings.BindingSuggestionConnect)); - teamExplorerController.DidNotReceive().ShowSonarQubePage(); + connectedModeManager.DidNotReceive().ShowManageBindingDialog(); connectAction.Action(notification); - teamExplorerController.Received().ShowSonarQubePage(); + connectedModeManager.Received().ShowManageBindingDialog(); } [TestMethod] @@ -122,17 +122,17 @@ public void Notify_LearnMoreAction_OpensDocumentationInBrowser() private BindingSuggestionHandler CreateTestSubject(SonarLintMode sonarLintMode, INotificationService notificationService = null, IIDEWindowService ideWindowService = null, - ITeamExplorerController teamExplorerController = null, + IConnectedModeManager connectedModeManager = null, IBrowserService browserService = null) { notificationService ??= Substitute.For(); var activeSolutionBoundTracker = Substitute.For(); ideWindowService ??= Substitute.For(); - teamExplorerController ??= Substitute.For(); + connectedModeManager ??= Substitute.For(); browserService ??= Substitute.For(); activeSolutionBoundTracker.CurrentConfiguration.Returns(new BindingConfiguration(new BoundServerProject("solution", "server project", new ServerConnection.SonarCloud("org")), sonarLintMode, "a-directory")); - return new BindingSuggestionHandler(notificationService, activeSolutionBoundTracker, ideWindowService, teamExplorerController, browserService); + return new BindingSuggestionHandler(notificationService, activeSolutionBoundTracker, ideWindowService, connectedModeManager, browserService); } } diff --git a/src/Integration/Binding/BindingSuggestionHandler.cs b/src/Integration/Binding/BindingSuggestionHandler.cs index 3be011760a..40394941ad 100644 --- a/src/Integration/Binding/BindingSuggestionHandler.cs +++ b/src/Integration/Binding/BindingSuggestionHandler.cs @@ -20,10 +20,10 @@ using System.ComponentModel.Composition; using SonarLint.VisualStudio.ConnectedMode.Binding.Suggestion; +using SonarLint.VisualStudio.ConnectedMode.UI; using SonarLint.VisualStudio.Core.Binding; using SonarLint.VisualStudio.Core.Notifications; using SonarLint.VisualStudio.Core; -using SonarLint.VisualStudio.Integration.TeamExplorer; namespace SonarLint.VisualStudio.Integration.Binding { @@ -34,20 +34,20 @@ internal class BindingSuggestionHandler : IBindingSuggestionHandler private readonly INotificationService notificationService; private readonly IActiveSolutionBoundTracker activeSolutionBoundTracker; private readonly IIDEWindowService ideWindowService; - private readonly ITeamExplorerController teamExplorerController; + private readonly IConnectedModeManager connectedModeManager; private readonly IBrowserService browserService; [ImportingConstructor] public BindingSuggestionHandler(INotificationService notificationService, IActiveSolutionBoundTracker activeSolutionBoundTracker, IIDEWindowService ideWindowService, - ITeamExplorerController teamExplorerController, + IConnectedModeManager connectedModeManager, IBrowserService browserService) { this.notificationService = notificationService; this.activeSolutionBoundTracker = activeSolutionBoundTracker; this.ideWindowService = ideWindowService; - this.teamExplorerController = teamExplorerController; + this.connectedModeManager = connectedModeManager; this.browserService = browserService; } @@ -62,7 +62,7 @@ public void Notify() : BindingStrings.BindingSuggetsionBindingConflict; var connectAction = new NotificationAction(BindingStrings.BindingSuggestionConnect, - _ => teamExplorerController.ShowSonarQubePage(), + _ => connectedModeManager.ShowManageBindingDialog(), true); var learnMoreAction = new NotificationAction(BindingStrings.BindingSuggestionLearnMore, _ => browserService.Navigate(DocumentationLinks.OpenInIdeBindingSetup), From 18bce3a31f2639eee13adffdc8e2d306ef6c7617 Mon Sep 17 00:00:00 2001 From: Gabriela Trutan Date: Mon, 7 Oct 2024 12:03:17 +0200 Subject: [PATCH 3/4] SLVS-1490 Refactor test class to use test initialize. --- .../Binding/BindingSuggestionHandlerTests.cs | 57 ++++++++++--------- 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/src/Integration.UnitTests/Binding/BindingSuggestionHandlerTests.cs b/src/Integration.UnitTests/Binding/BindingSuggestionHandlerTests.cs index 5ba5c834f6..d08a20b041 100644 --- a/src/Integration.UnitTests/Binding/BindingSuggestionHandlerTests.cs +++ b/src/Integration.UnitTests/Binding/BindingSuggestionHandlerTests.cs @@ -31,6 +31,24 @@ namespace SonarLint.VisualStudio.Integration.UnitTests.Binding; [TestClass] public class BindingSuggestionHandlerTests { + private BindingSuggestionHandler testSubject; + private INotificationService notificationService; + private IActiveSolutionBoundTracker activeSolutionBoundTracker; + private IIDEWindowService ideWindowService; + private IConnectedModeManager connectedModeManager; + private IBrowserService browserService; + + [TestInitialize] + public void TestInitialize() + { + notificationService = Substitute.For(); + activeSolutionBoundTracker = Substitute.For(); + ideWindowService = Substitute.For(); + connectedModeManager = Substitute.For(); + browserService = Substitute.For(); + testSubject = new BindingSuggestionHandler(notificationService, activeSolutionBoundTracker, ideWindowService, connectedModeManager, browserService); + } + [TestMethod] public void MefCtor_CheckExports() { @@ -47,9 +65,8 @@ public void MefCtor_CheckExports() [DataRow(SonarLintMode.Connected)] public void Notify_BringsWindowToFront(SonarLintMode sonarLintMode) { - var ideWindowService = Substitute.For(); + MockCurrentConfiguration(sonarLintMode); - var testSubject = CreateTestSubject(sonarLintMode: sonarLintMode, ideWindowService: ideWindowService); testSubject.Notify(); ideWindowService.Received().BringToFront(); @@ -58,9 +75,8 @@ public void Notify_BringsWindowToFront(SonarLintMode sonarLintMode) [TestMethod] public void Notify_WithStandaloneProject_PromptsToConnect() { - var notificationService = Substitute.For(); + MockCurrentConfiguration(SonarLintMode.Standalone); - var testSubject = CreateTestSubject(sonarLintMode: SonarLintMode.Standalone, notificationService: notificationService); testSubject.Notify(); notificationService.Received().ShowNotification(Arg.Is( @@ -73,9 +89,8 @@ public void Notify_WithStandaloneProject_PromptsToConnect() [TestMethod] public void Notify_WithBoundProject_ShowsConflictMessage() { - var notificationService = Substitute.For(); + MockCurrentConfiguration(SonarLintMode.Connected); - var testSubject = CreateTestSubject(sonarLintMode: SonarLintMode.Connected, notificationService: notificationService); testSubject.Notify(); notificationService.Received().ShowNotification(Arg.Is( @@ -86,13 +101,12 @@ public void Notify_WithBoundProject_ShowsConflictMessage() } [TestMethod] - public void Notify_ConnectAction_OpensSonarQubePage() + public void Notify_ConnectAction_ShowsManageBindingDialog() { - var notificationService = Substitute.For(); - var connectedModeManager = Substitute.For(); + MockCurrentConfiguration(SonarLintMode.Standalone); - var testSubject = CreateTestSubject(sonarLintMode: SonarLintMode.Standalone, notificationService: notificationService, connectedModeManager: connectedModeManager); testSubject.Notify(); + var notification = (Notification)notificationService.ReceivedCalls().Single().GetArguments().Single(); var connectAction = notification.Actions.First(x => x.CommandText.Equals(BindingStrings.BindingSuggestionConnect)); @@ -105,11 +119,10 @@ public void Notify_ConnectAction_OpensSonarQubePage() [TestMethod] public void Notify_LearnMoreAction_OpensDocumentationInBrowser() { - var notificationService = Substitute.For(); - var browserService = Substitute.For(); + MockCurrentConfiguration(SonarLintMode.Standalone); - var testSubject = CreateTestSubject(sonarLintMode: SonarLintMode.Standalone, notificationService: notificationService, browserService: browserService); testSubject.Notify(); + var notification = (Notification)notificationService.ReceivedCalls().Single().GetArguments().Single(); var connectAction = notification.Actions.First(x => x.CommandText.Equals(BindingStrings.BindingSuggestionLearnMore)); @@ -119,20 +132,10 @@ public void Notify_LearnMoreAction_OpensDocumentationInBrowser() browserService.Received().Navigate(DocumentationLinks.OpenInIdeBindingSetup); } - private BindingSuggestionHandler CreateTestSubject(SonarLintMode sonarLintMode, - INotificationService notificationService = null, - IIDEWindowService ideWindowService = null, - IConnectedModeManager connectedModeManager = null, - IBrowserService browserService = null) + private void MockCurrentConfiguration(SonarLintMode sonarLintMode) { - notificationService ??= Substitute.For(); - var activeSolutionBoundTracker = Substitute.For(); - ideWindowService ??= Substitute.For(); - connectedModeManager ??= Substitute.For(); - browserService ??= Substitute.For(); - - activeSolutionBoundTracker.CurrentConfiguration.Returns(new BindingConfiguration(new BoundServerProject("solution", "server project", new ServerConnection.SonarCloud("org")), sonarLintMode, "a-directory")); - - return new BindingSuggestionHandler(notificationService, activeSolutionBoundTracker, ideWindowService, connectedModeManager, browserService); + activeSolutionBoundTracker.CurrentConfiguration.Returns(new BindingConfiguration( + new BoundServerProject("solution", "server project", new ServerConnection.SonarCloud("org")), sonarLintMode, + "a-directory")); } } From fc42c3a94d876d173f4a3e44868c86e68410a353 Mon Sep 17 00:00:00 2001 From: Gabriela Trutan Date: Mon, 7 Oct 2024 16:07:15 +0200 Subject: [PATCH 4/4] SLVS-1490 Drop old class that was renamed and which was not removed during merge --- .../UI/ConnectedModeManagerTests.cs | 41 -------------- src/ConnectedMode/UI/ConnectedModeManager.cs | 53 ------------------- .../Binding/BindingSuggestionHandlerTests.cs | 4 +- 3 files changed, 2 insertions(+), 96 deletions(-) delete mode 100644 src/ConnectedMode.UnitTests/UI/ConnectedModeManagerTests.cs delete mode 100644 src/ConnectedMode/UI/ConnectedModeManager.cs diff --git a/src/ConnectedMode.UnitTests/UI/ConnectedModeManagerTests.cs b/src/ConnectedMode.UnitTests/UI/ConnectedModeManagerTests.cs deleted file mode 100644 index 2a1ad4ff42..0000000000 --- a/src/ConnectedMode.UnitTests/UI/ConnectedModeManagerTests.cs +++ /dev/null @@ -1,41 +0,0 @@ -/* - * SonarLint for Visual Studio - * Copyright (C) 2016-2024 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 SonarLint.VisualStudio.ConnectedMode.UI; -using SonarLint.VisualStudio.TestInfrastructure; - -namespace SonarLint.VisualStudio.ConnectedMode.UnitTests.UI -{ - [TestClass] - public class ConnectedModeManagerTests - { - [TestMethod] - public void MefCtor_CheckIsExported() - { - MefTestHelpers.CheckTypeCanBeImported( - MefTestHelpers.CreateExport(), - MefTestHelpers.CreateExport()); - } - - [TestMethod] - public void MefCtor_CheckIsSingleton() - => MefTestHelpers.CheckIsNonSharedMefComponent(); - } -} diff --git a/src/ConnectedMode/UI/ConnectedModeManager.cs b/src/ConnectedMode/UI/ConnectedModeManager.cs deleted file mode 100644 index 026ae6cbe0..0000000000 --- a/src/ConnectedMode/UI/ConnectedModeManager.cs +++ /dev/null @@ -1,53 +0,0 @@ -/* - * SonarLint for Visual Studio - * Copyright (C) 2016-2024 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.ComponentModel.Composition; -using System.Diagnostics.CodeAnalysis; -using System.Windows; -using SonarLint.VisualStudio.ConnectedMode.UI.ManageBinding; - -namespace SonarLint.VisualStudio.ConnectedMode.UI; - -public interface IConnectedModeManager -{ - void ShowManageBindingDialog(bool useSharedBindingOnInitialization = false); -} - -[Export(typeof(IConnectedModeManager))] -[PartCreationPolicy(CreationPolicy.NonShared)] -internal sealed class ConnectedModeManager : IConnectedModeManager -{ - private readonly IConnectedModeServices connectedModeServices; - private readonly IConnectedModeBindingServices connectedModeBindingServices; - - [ImportingConstructor] - public ConnectedModeManager(IConnectedModeServices connectedModeServices, IConnectedModeBindingServices connectedModeBindingServices) - { - this.connectedModeServices = connectedModeServices; - this.connectedModeBindingServices = connectedModeBindingServices; - } - - [ExcludeFromCodeCoverage] // UI, not really unit-testable - public void ShowManageBindingDialog(bool useSharedBindingOnInitialization = false) - { - var manageBindingDialog = new ManageBindingDialog(connectedModeServices, connectedModeBindingServices, useSharedBindingOnInitialization); - manageBindingDialog.ShowDialog(Application.Current.MainWindow); - } -} diff --git a/src/Integration.UnitTests/Binding/BindingSuggestionHandlerTests.cs b/src/Integration.UnitTests/Binding/BindingSuggestionHandlerTests.cs index 6aea7290ec..0fe1167a30 100644 --- a/src/Integration.UnitTests/Binding/BindingSuggestionHandlerTests.cs +++ b/src/Integration.UnitTests/Binding/BindingSuggestionHandlerTests.cs @@ -35,7 +35,7 @@ public class BindingSuggestionHandlerTests private INotificationService notificationService; private IActiveSolutionBoundTracker activeSolutionBoundTracker; private IIDEWindowService ideWindowService; - private IConnectedModeManager connectedModeManager; + private IConnectedModeUIManager connectedModeManager; private IBrowserService browserService; [TestInitialize] @@ -44,7 +44,7 @@ public void TestInitialize() notificationService = Substitute.For(); activeSolutionBoundTracker = Substitute.For(); ideWindowService = Substitute.For(); - connectedModeManager = Substitute.For(); + connectedModeManager = Substitute.For(); browserService = Substitute.For(); testSubject = new BindingSuggestionHandler(notificationService, activeSolutionBoundTracker, ideWindowService, connectedModeManager, browserService); }