Skip to content

Commit

Permalink
SLVS-1406 Add binding changed trigger to ActiveSolutionBoundTracker (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
georgii-borovinskikh-sonarsource authored and vnaskos-sonar committed Sep 19, 2024
1 parent a995066 commit 8619648
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 15 deletions.
5 changes: 5 additions & 0 deletions src/Core/Binding/IActiveSolutionBoundTracker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@

namespace SonarLint.VisualStudio.Core.Binding
{
public interface IActiveSolutionChangedHandler
{
void HandleBindingChange(bool isBindingCleared);
}

/// <summary>
/// Allows checking if the current Visual Studio solution is bound to a SonarQube project or not
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ public void ActiveSolutionBoundTracker_Changes()
ConfigureSolutionBinding(null);

// Act
host.VisualStateManager.ClearBoundProject();
testSubject.HandleBindingChange(true);

// Assert
testSubject.CurrentConfiguration.Mode.Should().Be(SonarLintMode.Standalone, "Unbound solution should report false activation");
Expand All @@ -235,7 +235,7 @@ public void ActiveSolutionBoundTracker_Changes()
// Case 2: Set bound project
ConfigureSolutionBinding(boundProject);
// Act
host.VisualStateManager.SetBoundProject(new Uri("http://localhost"), null, "project123");
testSubject.HandleBindingChange(false);

// Assert
testSubject.CurrentConfiguration.Mode.Should().Be(SonarLintMode.Connected, "Bound solution should report true activation");
Expand Down Expand Up @@ -307,7 +307,7 @@ public void ActiveSolutionBoundTracker_Changes()
// Act
testSubject.Dispose();
ConfigureSolutionBinding(boundProject);
host.VisualStateManager.ClearBoundProject();
testSubject.HandleBindingChange(true);

// Assert
eventCounter.PreSolutionBindingChangedCount.Should().Be(5, "Once disposed should stop raising the event");
Expand Down Expand Up @@ -349,13 +349,53 @@ public void OnBindingStateChanged_NewConfiguration_EventsRaisedInCorrectOrder()
// Assert
// Different config so event should be raised
eventCounter.PreSolutionBindingChangedCount.Should().Be(1);
eventCounter.PreSolutionBindingUpdatedCount.Should().Be(0);
eventCounter.SolutionBindingChangedCount.Should().Be(1);
eventCounter.SolutionBindingUpdatedCount.Should().Be(0);

eventCounter.RaisedEventNames.Should().HaveCount(2);
eventCounter.RaisedEventNames[0].Should().Be(nameof(testSubject.PreSolutionBindingChanged));
eventCounter.RaisedEventNames[1].Should().Be(nameof(testSubject.SolutionBindingChanged));
}
}

[TestMethod]
public void HandleBindingChange_NewConfiguration_EventsRaisedInCorrectOrder()
{
// Arrange
var initialProject = new BoundServerProject(
"solution",
"projectKey",
new ServerConnection.SonarCloud("myOrgKey"));

// Set the current configuration used by the tracker
ConfigureSolutionBinding(initialProject);
using (var testSubject = CreateTestSubject(this.host, this.activeSolutionTracker, this.configProvider, loggerMock.Object))
{
var eventCounter = new EventCounter(testSubject);

// Now configure the provider to return a different configuration
var newProject = new BoundServerProject(
"solution",
"projectKey",
new ServerConnection.SonarCloud("myOrgKey_DIFFERENT"));
ConfigureSolutionBinding(newProject);

// Act - simulate the binding state changing in the Team explorer section.
// The project configuration hasn't changed (it doesn't matter what properties
// we pass here; they aren't used when raising the event.)
testSubject.HandleBindingChange(false);

// Assert
// Different config so event should be raised
eventCounter.PreSolutionBindingChangedCount.Should().Be(1);
eventCounter.PreSolutionBindingUpdatedCount.Should().Be(0);
eventCounter.SolutionBindingChangedCount.Should().Be(1);
eventCounter.SolutionBindingUpdatedCount.Should().Be(0);

eventCounter.RaisedEventNames.Should().HaveCount(2);
eventCounter.RaisedEventNames[0].Should().Be("PreSolutionBindingChanged");
eventCounter.RaisedEventNames[1].Should().Be("SolutionBindingChanged");
eventCounter.RaisedEventNames[0].Should().Be(nameof(testSubject.PreSolutionBindingChanged));
eventCounter.RaisedEventNames[1].Should().Be(nameof(testSubject.SolutionBindingChanged));
}
}

Expand Down Expand Up @@ -521,6 +561,25 @@ public void SolutionBindingUpdated_WhenClearBoundProject_NotRaised()
eventCounter.SolutionBindingChangedCount.Should().Be(0);
}
}

[TestMethod]
public void HandleBindingChange_WhenClearBoundProject_NotRaised()
{
// Arrange
using (var testSubject = CreateTestSubject(this.host, this.activeSolutionTracker, this.configProvider, loggerMock.Object))
{
var eventCounter = new EventCounter(testSubject);

// Act
testSubject.HandleBindingChange(true);

// Assert
eventCounter.PreSolutionBindingUpdatedCount.Should().Be(0);
eventCounter.SolutionBindingUpdatedCount.Should().Be(0);
eventCounter.PreSolutionBindingChangedCount.Should().Be(0);
eventCounter.SolutionBindingChangedCount.Should().Be(0);
}
}

[TestMethod]
public void SolutionBindingUpdated_WhenSetBoundProject_EventsRaisedInExpectedOrder()
Expand All @@ -540,8 +599,31 @@ public void SolutionBindingUpdated_WhenSetBoundProject_EventsRaisedInExpectedOrd
eventCounter.SolutionBindingChangedCount.Should().Be(0);

eventCounter.RaisedEventNames.Should().HaveCount(2);
eventCounter.RaisedEventNames[0].Should().Be("PreSolutionBindingUpdated");
eventCounter.RaisedEventNames[1].Should().Be("SolutionBindingUpdated");
eventCounter.RaisedEventNames[0].Should().Be(nameof(testSubject.PreSolutionBindingUpdated));
eventCounter.RaisedEventNames[1].Should().Be(nameof(testSubject.SolutionBindingUpdated));
}
}

[TestMethod]
public void HandleBindingChange_WhenSetBoundProject_EventsRaisedInExpectedOrder()
{
// Arrange
using (var testSubject = CreateTestSubject(this.host, this.activeSolutionTracker, this.configProvider, loggerMock.Object))
{
var eventCounter = new EventCounter(testSubject);

// Act
testSubject.HandleBindingChange(false);

// Assert
eventCounter.PreSolutionBindingUpdatedCount.Should().Be(1);
eventCounter.SolutionBindingUpdatedCount.Should().Be(1);
eventCounter.PreSolutionBindingChangedCount.Should().Be(0);
eventCounter.SolutionBindingChangedCount.Should().Be(0);

eventCounter.RaisedEventNames.Should().HaveCount(2);
eventCounter.RaisedEventNames[0].Should().Be(nameof(testSubject.PreSolutionBindingUpdated));
eventCounter.RaisedEventNames[1].Should().Be(nameof(testSubject.SolutionBindingUpdated));
}
}

Expand All @@ -566,8 +648,8 @@ public void GitRepoUpdated_SolutionBindingUpdatedEventsRaised()
eventCounter.SolutionBindingChangedCount.Should().Be(0);

eventCounter.RaisedEventNames.Should().HaveCount(2);
eventCounter.RaisedEventNames[0].Should().Be("PreSolutionBindingUpdated");
eventCounter.RaisedEventNames[1].Should().Be("SolutionBindingUpdated");
eventCounter.RaisedEventNames[0].Should().Be(nameof(testSubject.PreSolutionBindingUpdated));
eventCounter.RaisedEventNames[1].Should().Be(nameof(testSubject.SolutionBindingUpdated));
}
}

Expand Down
25 changes: 19 additions & 6 deletions src/Integration/MefServices/ActiveSolutionBoundTracker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,9 @@ namespace SonarLint.VisualStudio.Integration
/// UIContext.
/// </remarks>
[Export(typeof(IActiveSolutionBoundTracker))]
[Export(typeof(IActiveSolutionChangedHandler))]
[PartCreationPolicy(CreationPolicy.Shared)]
internal sealed class ActiveSolutionBoundTracker : IActiveSolutionBoundTracker, IDisposable, IPartImportsSatisfiedNotification
internal sealed class ActiveSolutionBoundTracker : IActiveSolutionBoundTracker, IActiveSolutionChangedHandler, IDisposable, IPartImportsSatisfiedNotification
{
private readonly IHost extensionHost;
private readonly IActiveSolutionTracker solutionTracker;
Expand All @@ -52,6 +53,7 @@ internal sealed class ActiveSolutionBoundTracker : IActiveSolutionBoundTracker,
private readonly IConfigScopeUpdater configScopeUpdater;
private readonly ILogger logger;
private readonly uint boundSolutionContextCookie;
private bool disposed;

public event EventHandler<ActiveSolutionBindingEventArgs> PreSolutionBindingChanged;
public event EventHandler<ActiveSolutionBindingEventArgs> SolutionBindingChanged;
Expand Down Expand Up @@ -95,6 +97,21 @@ public ActiveSolutionBoundTracker([Import(typeof(SVsServiceProvider))] IServiceP
this.gitEventsMonitor.HeadChanged += GitEventsMonitor_HeadChanged;
}

public void HandleBindingChange(bool isBindingCleared)
{
if (disposed)
{
return;
}

this.RaiseAnalyzersChangedIfBindingChanged(GetBindingConfiguration(), isBindingCleared);
}

private void OnBindingStateChanged(object sender, BindingStateEventArgs e)
{
HandleBindingChange(e.IsBindingCleared);
}

private BindingConfiguration GetBindingConfiguration()
{
return configurationProvider.GetConfiguration();
Expand Down Expand Up @@ -159,11 +176,6 @@ await Core.WebServiceHelper.SafeServiceCallAsync(() => sonarQubeService.ConnectA
}
}

private void OnBindingStateChanged(object sender, BindingStateEventArgs e)
{
this.RaiseAnalyzersChangedIfBindingChanged(GetBindingConfiguration(), e.IsBindingCleared);
}

private void RaiseAnalyzersChangedIfBindingChanged(BindingConfiguration newBindingConfiguration, bool? isBindingCleared = null)
{
configScopeUpdater.UpdateConfigScopeForCurrentSolution(newBindingConfiguration.Project);
Expand Down Expand Up @@ -206,6 +218,7 @@ private void Dispose(bool disposing)
{
if (disposing)
{
this.disposed = true;
this.solutionTracker.ActiveSolutionChanged -= this.OnActiveSolutionChanged;
this.extensionHost.VisualStateManager.BindingStateChanged -= this.OnBindingStateChanged;
this.gitEventsMonitor.HeadChanged -= GitEventsMonitor_HeadChanged;
Expand Down

0 comments on commit 8619648

Please sign in to comment.