Skip to content

Commit

Permalink
Implement PR feedback
Browse files Browse the repository at this point in the history
  • Loading branch information
vnaskos-sonar committed Jan 30, 2025
1 parent c03b84b commit 4ab347b
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,24 +22,27 @@
using SonarLint.VisualStudio.ConnectedMode.UI;
using SonarLint.VisualStudio.Core;
using SonarLint.VisualStudio.Core.Binding;
using SonarLint.VisualStudio.Core.ConfigurationScope;
using SonarLint.VisualStudio.Core.Notifications;
using SonarLint.VisualStudio.Core.Telemetry;
using SonarLint.VisualStudio.TestInfrastructure;

namespace SonarLint.VisualStudio.ConnectedMode.UnitTests.Promote;

[TestClass]
public class PromoteGoldBarTests
public class PromoteNotificationTests
{
private const string LanguageToPromote = "TSQL";
private const string DefaultConfigurationScopeId = "CONFIG_SCOPE_ID";
private readonly List<Language> languageToPromote = [Language.TSql];

private INotificationService notificationService;
private IDoNotShowAgainNotificationAction doNotShowAgainNotificationAction;
private IActiveSolutionBoundTracker activeSolutionBoundTracker;
private IBrowserService browserService;
private ITelemetryManager telemetryManager;
private IConnectedModeUIManager connectedModeUiManager;
private PromoteGoldBar testSubject;
private IActiveConfigScopeTracker activeConfigScopeTracker;
private PromoteNotification testSubject;

[TestInitialize]
public void TestInitialize()
Expand All @@ -50,44 +53,81 @@ public void TestInitialize()
browserService = Substitute.For<IBrowserService>();
telemetryManager = Substitute.For<ITelemetryManager>();
connectedModeUiManager = Substitute.For<IConnectedModeUIManager>();
testSubject = new PromoteGoldBar(notificationService, doNotShowAgainNotificationAction, activeSolutionBoundTracker, browserService, telemetryManager, connectedModeUiManager);
activeConfigScopeTracker = Substitute.For<IActiveConfigScopeTracker>();

activeConfigScopeTracker.Current.Returns(new Core.ConfigurationScope.ConfigurationScope(DefaultConfigurationScopeId));
activeSolutionBoundTracker.CurrentConfiguration.Returns(BindingConfiguration.Standalone);

testSubject = new PromoteNotification(
notificationService,
doNotShowAgainNotificationAction,
activeSolutionBoundTracker,
browserService,
telemetryManager,
connectedModeUiManager,
activeConfigScopeTracker);
}

[TestMethod]
public void MefCtor_CheckExports() =>
MefTestHelpers.CheckTypeCanBeImported<PromoteGoldBar, IPromoteGoldBar>(
MefTestHelpers.CheckTypeCanBeImported<PromoteNotification, IPromoteNotification>(
MefTestHelpers.CreateExport<INotificationService>(),
MefTestHelpers.CreateExport<IDoNotShowAgainNotificationAction>(),
MefTestHelpers.CreateExport<IActiveSolutionBoundTracker>(),
MefTestHelpers.CreateExport<IBrowserService>(),
MefTestHelpers.CreateExport<ITelemetryManager>(),
MefTestHelpers.CreateExport<IConnectedModeUIManager>());
MefTestHelpers.CreateExport<IConnectedModeUIManager>(),
MefTestHelpers.CreateExport<IActiveConfigScopeTracker>());

[TestMethod]
public void MefCtor_CheckIsSingleton() => MefTestHelpers.CheckIsSingletonMefComponent<PromoteGoldBar>();
public void MefCtor_CheckIsSingleton() => MefTestHelpers.CheckIsSingletonMefComponent<PromoteNotification>();

[TestMethod]
public void PromoteConnectedMode_WhenConfigScopeMissMatch_DoesNotShowNotification()
{
using var _ = new AssertIgnoreScope();
testSubject.PromoteConnectedMode("ANOTHER_CONFIG_SCOPE_ID", languageToPromote);

notificationService.DidNotReceive().ShowNotification(Arg.Any<INotification>());
}

[TestMethod]
public void PromoteConnectedMode_WhenInConnectedMode_DoesNotShowNotification()
{
using var _ = new AssertIgnoreScope();
var inConnectedMode = new BindingConfiguration(
new BoundServerProject("test", "test", new ServerConnection.SonarQube(new Uri("https://localhost:9000"))),
SonarLintMode.Connected,
"C:\\path");
activeSolutionBoundTracker.CurrentConfiguration.Returns(inConnectedMode);

testSubject.PromoteConnectedMode(DefaultConfigurationScopeId, languageToPromote);

notificationService.DidNotReceive().ShowNotification(Arg.Any<INotification>());
}

[TestMethod]
public void PromoteConnectedMode_ShowsNotification_WithId()
{
testSubject.PromoteConnectedMode(LanguageToPromote);
testSubject.PromoteConnectedMode(DefaultConfigurationScopeId, languageToPromote);

notificationService.Received(1).ShowNotification(Arg.Is<Notification>(n => n.Id == "PromoteNotification"));
notificationService.Received(1).ShowNotification(Arg.Is<Notification>(n => n.Id == $"PromoteNotification.{languageToPromote[0].Id}"));
}

[TestMethod]
public void PromoteConnectedMode_ShowsNotification_WithMessageThatContainsTheLanguageToPromote()
{
testSubject.PromoteConnectedMode(LanguageToPromote);
testSubject.PromoteConnectedMode(DefaultConfigurationScopeId, languageToPromote);

notificationService.Received(1).ShowNotification(Arg.Is<Notification>(n =>
n.Message == string.Format(Resources.PromoteConnectedModeLanguagesMessage, LanguageToPromote)
n.Message == string.Format(Resources.PromoteConnectedModeLanguagesMessage, languageToPromote[0].Name)
));
}

[TestMethod]
public void PromoteConnectedMode_ShowsNotification_WithCorrectActions()
{
testSubject.PromoteConnectedMode(LanguageToPromote);
testSubject.PromoteConnectedMode(DefaultConfigurationScopeId, languageToPromote);

notificationService.Received(1).ShowNotification(Arg.Is<Notification>(n =>
n.Actions.ToList().Count == 4 &&
Expand All @@ -101,7 +141,7 @@ public void PromoteConnectedMode_ShowsNotification_WithCorrectActions()
[TestMethod]
public void PromoteConnectedMode_BindAction_ShowsManageBindingDialog()
{
testSubject.PromoteConnectedMode(LanguageToPromote);
testSubject.PromoteConnectedMode(DefaultConfigurationScopeId, languageToPromote);
var notification = (Notification)notificationService.ReceivedCalls().Single().GetArguments()[0];
var bindAction = notification.Actions.First(a => a.CommandText == Resources.PromoteBind);

Expand All @@ -113,7 +153,7 @@ public void PromoteConnectedMode_BindAction_ShowsManageBindingDialog()
[TestMethod]
public void PromoteConnectedMode_SonarQubeCloudAction_NavigatesToCorrectUrl()
{
testSubject.PromoteConnectedMode(LanguageToPromote);
testSubject.PromoteConnectedMode(DefaultConfigurationScopeId, languageToPromote);
var notification = (Notification) notificationService.ReceivedCalls().Single().GetArguments()[0];
var sonarQubeCloudAction = notification.Actions.First(a => a.CommandText == Resources.PromoteSonarQubeCloud);

Expand All @@ -125,7 +165,7 @@ public void PromoteConnectedMode_SonarQubeCloudAction_NavigatesToCorrectUrl()
[TestMethod]
public void PromoteConnectedMode_LearnMoreAction_NavigatesToCorrectUrl()
{
testSubject.PromoteConnectedMode(LanguageToPromote);
testSubject.PromoteConnectedMode(DefaultConfigurationScopeId, languageToPromote);
var notification = (Notification) notificationService.ReceivedCalls().Single().GetArguments()[0];
var learnMoreAction = notification.Actions.First(a => a.CommandText == Resources.PromoteLearnMore);

Expand All @@ -139,7 +179,7 @@ public void OnActiveSolutionBindingChanged_ConnectedMode_ClosesNotification()
{
var eventArgs = new ActiveSolutionBindingEventArgs(new BindingConfiguration(null, SonarLintMode.Connected, null));

testSubject.PromoteConnectedMode(LanguageToPromote);
testSubject.PromoteConnectedMode(DefaultConfigurationScopeId, languageToPromote);
activeSolutionBoundTracker.SolutionBindingChanged += Raise.EventWith(this, eventArgs);

notificationService.Received(1).CloseNotification();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,51 +22,69 @@
using SonarLint.VisualStudio.ConnectedMode.UI;
using SonarLint.VisualStudio.Core;
using SonarLint.VisualStudio.Core.Binding;
using SonarLint.VisualStudio.Core.ConfigurationScope;
using SonarLint.VisualStudio.Core.Notifications;
using SonarLint.VisualStudio.Core.Telemetry;

namespace SonarLint.VisualStudio.ConnectedMode.Promote;

public interface IPromoteGoldBar
public interface IPromoteNotification
{
void PromoteConnectedMode(string languagesToPromote);
void PromoteConnectedMode(string configurationScopeId, List<Language> languagesToPromote);
}

[Export(typeof(IPromoteGoldBar))]
[Export(typeof(IPromoteNotification))]
[PartCreationPolicy(CreationPolicy.Shared)]
public sealed class PromoteGoldBar : IPromoteGoldBar, IDisposable
public sealed class PromoteNotification : IPromoteNotification, IDisposable
{
private readonly INotificationService notificationService;
private readonly IDoNotShowAgainNotificationAction doNotShowAgainNotificationAction;
private readonly IActiveSolutionBoundTracker activeSolutionBoundTracker;
private readonly IBrowserService browserService;
private readonly ITelemetryManager telemetryManager;
private readonly IConnectedModeUIManager connectedModeUiManager;
private readonly IActiveConfigScopeTracker activeConfigScopeTracker;

[ImportingConstructor]
public PromoteGoldBar(
public PromoteNotification(
INotificationService notificationService,
IDoNotShowAgainNotificationAction doNotShowAgainNotificationAction,
IActiveSolutionBoundTracker activeSolutionBoundTracker,
IBrowserService browserService,
ITelemetryManager telemetryManager,
IConnectedModeUIManager connectedModeUiManager)
IConnectedModeUIManager connectedModeUiManager,
IActiveConfigScopeTracker activeConfigScopeTracker)
{
this.notificationService = notificationService;
this.doNotShowAgainNotificationAction = doNotShowAgainNotificationAction;
this.activeSolutionBoundTracker = activeSolutionBoundTracker;
this.browserService = browserService;
this.telemetryManager = telemetryManager;
this.connectedModeUiManager = connectedModeUiManager;
this.activeConfigScopeTracker = activeConfigScopeTracker;

this.activeSolutionBoundTracker.SolutionBindingChanged += OnActiveSolutionBindingChanged;
}

public void PromoteConnectedMode(string languagesToPromote)
public void PromoteConnectedMode(string configurationScopeId, List<Language> languagesToPromote)
{
var currentConfigScope = activeConfigScopeTracker.Current;

if (currentConfigScope is null || currentConfigScope.Id != configurationScopeId)
{
Debug.Fail($"[Promote] Config scope miss match: {currentConfigScope} does not match {configurationScopeId}");
return;
}

if (activeSolutionBoundTracker.CurrentConfiguration.Mode == SonarLintMode.Connected)
{
Debug.Fail("Cannot promote extra language when already in connected");
return;
}

var notification = new Notification(
id: "PromoteNotification",
message: string.Format(Resources.PromoteConnectedModeLanguagesMessage, languagesToPromote),
id: $"PromoteNotification.{string.Join(".", languagesToPromote.Select(x => x.Id))}",
message: string.Format(Resources.PromoteConnectedModeLanguagesMessage, string.Join(", ", languagesToPromote.Select(x => x.Name))),
actions:
[
new NotificationAction(Resources.PromoteBind, _ => OnBind(), false),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,31 +28,33 @@ namespace SonarLint.VisualStudio.SLCore.Listeners.UnitTests.Implementation;
[TestClass]
public class PromoteListenerTests
{
private IPromoteGoldBar promoteGoldBar;
private IPromoteNotification promoteNotification;
private PromoteListener testSubject;

[TestInitialize]
public void TestInitialize()
{
promoteGoldBar = Substitute.For<IPromoteGoldBar>();
testSubject = new PromoteListener(promoteGoldBar);
promoteNotification = Substitute.For<IPromoteNotification>();
testSubject = new PromoteListener(promoteNotification);
}

[TestMethod]
public void MefCtor_CheckExports() =>
MefTestHelpers.CheckTypeCanBeImported<PromoteListener, ISLCoreListener>(
MefTestHelpers.CreateExport<IPromoteGoldBar>());
MefTestHelpers.CreateExport<IPromoteNotification>());

[TestMethod]
public void MefCtor_CheckIsSingleton() => MefTestHelpers.CheckIsSingletonMefComponent<PromoteListener>();

[TestMethod]
public void PromoteExtraEnabledLanguagesInConnectedMode_DisplaysGoldBarWithCommaSeparatedLanguages()
public void PromoteExtraEnabledLanguagesInConnectedMode_DisplaysGoldBar()
{
var parameters = new PromoteExtraEnabledLanguagesInConnectedModeParams("CONFIGURATION_SCOPE_ID", [Language.TSQL, Language.PLSQL]);
var parameters = new PromoteExtraEnabledLanguagesInConnectedModeParams("CONFIGURATION_SCOPE_ID", [Language.TSQL]);

testSubject.PromoteExtraEnabledLanguagesInConnectedMode(parameters);

promoteGoldBar.Received().PromoteConnectedMode("TSQL, PLSQL");
promoteNotification.Received().PromoteConnectedMode(
Arg.Is("CONFIGURATION_SCOPE_ID"),
Arg.Is<List<VisualStudio.Core.Language>>(x => x.Count == 1 && x[0] == VisualStudio.Core.Language.TSql));
}
}
9 changes: 6 additions & 3 deletions src/SLCore.Listeners/Implementation/PromoteListener.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

using System.ComponentModel.Composition;
using SonarLint.VisualStudio.ConnectedMode.Promote;
using SonarLint.VisualStudio.SLCore.Common.Helpers;
using SonarLint.VisualStudio.SLCore.Core;
using SonarLint.VisualStudio.SLCore.Listener.Promote;

Expand All @@ -28,11 +29,13 @@ namespace SonarLint.VisualStudio.SLCore.Listeners.Implementation;
[Export(typeof(ISLCoreListener))]
[PartCreationPolicy(CreationPolicy.Shared)]
[method: ImportingConstructor]
public class PromoteListener(IPromoteGoldBar promoteGoldBar) : IPromoteListener
public class PromoteListener(IPromoteNotification promoteNotification) : IPromoteListener
{
public void PromoteExtraEnabledLanguagesInConnectedMode(PromoteExtraEnabledLanguagesInConnectedModeParams parameters)
{
var languagesToPromote = string.Join(", ", parameters.languagesToPromote);
promoteGoldBar.PromoteConnectedMode(languagesToPromote);
var languagesToPromote = parameters.languagesToPromote
.Select(x => x.ConvertToCoreLanguage())
.ToList();
promoteNotification.PromoteConnectedMode(parameters.configurationScopeId, languagesToPromote);
}
}

0 comments on commit 4ab347b

Please sign in to comment.