diff --git a/src/SLCore.UnitTests/State/ActiveConfigScopeTrackerTests.cs b/src/SLCore.UnitTests/State/ActiveConfigScopeTrackerTests.cs index 3e4ed37cc..f5cb30962 100644 --- a/src/SLCore.UnitTests/State/ActiveConfigScopeTrackerTests.cs +++ b/src/SLCore.UnitTests/State/ActiveConfigScopeTrackerTests.cs @@ -18,6 +18,7 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +using System.ComponentModel; using SonarLint.VisualStudio.Core; using SonarLint.VisualStudio.Core.Synchronization; using SonarLint.VisualStudio.SLCore.Core; @@ -38,6 +39,7 @@ public class ActiveConfigScopeTrackerTests private ISLCoreServiceProvider serviceProvider; private IAsyncLockFactory asyncLockFactory; private IThreadHandling threadHandling; + private EventHandler currentConfigScopeChangedEventHandler; [TestInitialize] public void TestInitialize() @@ -50,8 +52,10 @@ public void TestInitialize() threadHandling = Substitute.For(); ConfigureServiceProvider(isServiceAvailable:true); ConfigureAsyncLockFactory(); + currentConfigScopeChangedEventHandler = Substitute.For(); testSubject = new ActiveConfigScopeTracker(serviceProvider, asyncLockFactory, threadHandling); + testSubject.CurrentConfigurationScopeChanged += currentConfigScopeChangedEventHandler; } [TestMethod] @@ -80,6 +84,7 @@ public void SetCurrentConfigScope_SetsUnboundScope() VerifyThreadHandling(); VerifyServiceAddCall(); VerifyLockTakenSynchronouslyAndReleased(); + VerifyCurrentConfigurationScopeChangedRaised(); } [TestMethod] @@ -95,6 +100,7 @@ public void TryUpdateRootOnCurrentConfigScope_ConfigScopeSame_Updates() result.Should().BeTrue(); testSubject.currentConfigScope.Should().BeEquivalentTo(new ConfigurationScope(configScopeId, connectionId, sonarProjectKey, "some root", isReady)); + VerifyCurrentConfigurationScopeChangedRaised(); } [TestMethod] @@ -110,6 +116,7 @@ public void TryUpdateRootOnCurrentConfigScope_ConfigScopeDifferent_DoesNotUpdate result.Should().BeFalse(); testSubject.currentConfigScope.Should().BeEquivalentTo(new ConfigurationScope(configScopeId, connectionId, sonarProjectKey, isReadyForAnalysis: isReady)); + VerifyCurrentConfigurationScopeChangedNotRaised(); } [TestMethod] @@ -125,6 +132,7 @@ public void TryUpdateAnalysisReadinessOnCurrentConfigScope_ConfigScopeSame_Updat result.Should().BeTrue(); testSubject.currentConfigScope.Should().BeEquivalentTo(new ConfigurationScope(configScopeId, connectionId, sonarProjectKey, root, true)); + VerifyCurrentConfigurationScopeChangedRaised(); } [TestMethod] @@ -140,6 +148,7 @@ public void TryUpdateAnalysisReadinessOnCurrentConfigScope_ConfigScopeDifferent_ result.Should().BeFalse(); testSubject.currentConfigScope.Should().BeEquivalentTo(new ConfigurationScope(configScopeId, connectionId, sonarProjectKey, root)); + VerifyCurrentConfigurationScopeChangedNotRaised(); } [TestMethod] @@ -155,6 +164,7 @@ public void SetCurrentConfigScope_SetsBoundScope() VerifyThreadHandling(); VerifyServiceAddCall(); VerifyLockTakenSynchronouslyAndReleased(); + VerifyCurrentConfigurationScopeChangedRaised(); } [TestMethod] @@ -174,6 +184,7 @@ public void SetCurrentConfigScope_CurrentScopeExists_UpdatesBoundScope() VerifyThreadHandling(); VerifyServiceUpdateCall(); VerifyLockTakenSynchronouslyAndReleased(); + VerifyCurrentConfigurationScopeChangedRaised(); } [TestMethod] @@ -185,6 +196,7 @@ public void SetCurrentConfigScope_ServiceUnavailable_Throws() act.Should().ThrowExactly().WithMessage(SLCoreStrings.ServiceProviderNotInitialized); VerifyThreadHandling(); + VerifyCurrentConfigurationScopeChangedNotRaised(); } [TestMethod] @@ -199,6 +211,7 @@ public void SetCurrentConfigScope_UpdateConfigScopeWithDifferentId_Throws() act.Should().ThrowExactly().WithMessage(SLCoreStrings.ConfigScopeConflict); VerifyThreadHandling(); + VerifyCurrentConfigurationScopeChangedNotRaised(); } [TestMethod] @@ -212,6 +225,7 @@ public void RemoveCurrentConfigScope_RemovesScope() configScopeService.Received().DidRemoveConfigurationScope(Arg.Is(p => p.removedId == configScopeId)); VerifyThreadHandling(); VerifyLockTakenSynchronouslyAndReleased(); + VerifyCurrentConfigurationScopeChangedRaised(); } [TestMethod] @@ -222,6 +236,7 @@ public void RemoveCurrentConfigScope_NoCurrentScope_DoesNothing() configScopeService.ReceivedCalls().Count().Should().Be(0); VerifyThreadHandling(); VerifyLockTakenSynchronouslyAndReleased(); + VerifyCurrentConfigurationScopeChangedNotRaised(); } [TestMethod] @@ -234,6 +249,7 @@ public void RemoveCurrentConfigScope_ServiceUnavailable_Throws() act.Should().ThrowExactly().WithMessage(SLCoreStrings.ServiceProviderNotInitialized); VerifyThreadHandling(); + VerifyCurrentConfigurationScopeChangedNotRaised(); } [TestMethod] @@ -279,6 +295,7 @@ public void Reset_SetsCurrentScopeToNull() serviceProvider.ReceivedCalls().Count().Should().Be(0); VerifyThreadHandling(); VerifyLockTakenSynchronouslyAndReleased(); + VerifyCurrentConfigurationScopeChangedRaised(); } [TestMethod] @@ -335,6 +352,16 @@ private void ConfigureServiceProvider(bool isServiceAvailable) }); } + private void VerifyCurrentConfigurationScopeChangedRaised() + { + currentConfigScopeChangedEventHandler.Received(1).Invoke(testSubject, Arg.Any()); + } + + private void VerifyCurrentConfigurationScopeChangedNotRaised() + { + currentConfigScopeChangedEventHandler.DidNotReceive().Invoke(testSubject, Arg.Any()); + } + private class ConfigurationScopeDtoComparer : IEqualityComparer { public bool Equals(ConfigurationScopeDto x, ConfigurationScopeDto y) diff --git a/src/SLCore/State/ActiveConfigScopeTracker.cs b/src/SLCore/State/ActiveConfigScopeTracker.cs index c874c2271..e3c553a71 100644 --- a/src/SLCore/State/ActiveConfigScopeTracker.cs +++ b/src/SLCore/State/ActiveConfigScopeTracker.cs @@ -18,9 +18,7 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using System; using System.ComponentModel.Composition; -using System.Diagnostics; using SonarLint.VisualStudio.Core; using SonarLint.VisualStudio.Core.Synchronization; using SonarLint.VisualStudio.SLCore.Core; @@ -43,6 +41,8 @@ public interface IActiveConfigScopeTracker : IDisposable bool TryUpdateRootOnCurrentConfigScope(string id, string root); bool TryUpdateAnalysisReadinessOnCurrentConfigScope(string id, bool isReady); + + event EventHandler CurrentConfigurationScopeChanged; } public record ConfigurationScope( @@ -107,23 +107,26 @@ public void SetCurrentConfigScope(string id, string connectionId = null, string { configurationScopeService.DidUpdateBinding(new DidUpdateBindingParams(id, GetBinding(connectionId, sonarProjectKey))); currentConfigScope = currentConfigScope with { ConnectionId = connectionId, SonarProjectId = sonarProjectKey }; - return; } - - configurationScopeService.DidAddConfigurationScopes(new DidAddConfigurationScopesParams([ - new ConfigurationScopeDto(id, id, true, GetBinding(connectionId, sonarProjectKey))])); - currentConfigScope = new ConfigurationScope(id, connectionId, sonarProjectKey); + else + { + configurationScopeService.DidAddConfigurationScopes(new DidAddConfigurationScopesParams([ + new ConfigurationScopeDto(id, id, true, GetBinding(connectionId, sonarProjectKey))])); + currentConfigScope = new ConfigurationScope(id, connectionId, sonarProjectKey); + } } + + OnCurrentConfigurationScopeChanged(); } public void Reset() { threadHandling.ThrowIfOnUIThread(); - using (asyncLock.Acquire()) { currentConfigScope = null; } + OnCurrentConfigurationScopeChanged(); } public void RemoveCurrentConfigScope() @@ -146,6 +149,8 @@ public void RemoveCurrentConfigScope() new DidRemoveConfigurationScopeParams(currentConfigScope.Id)); currentConfigScope = null; } + + OnCurrentConfigurationScopeChanged(); } public bool TryUpdateRootOnCurrentConfigScope(string id, string root) @@ -158,8 +163,9 @@ public bool TryUpdateRootOnCurrentConfigScope(string id, string root) } currentConfigScope = currentConfigScope with { RootPath = root }; - return true; } + OnCurrentConfigurationScopeChanged(); + return true; } public bool TryUpdateAnalysisReadinessOnCurrentConfigScope(string id, bool isReady) @@ -172,10 +178,13 @@ public bool TryUpdateAnalysisReadinessOnCurrentConfigScope(string id, bool isRea } currentConfigScope = currentConfigScope with { isReadyForAnalysis = isReady}; - return true; } + OnCurrentConfigurationScopeChanged(); + return true; } + public event EventHandler CurrentConfigurationScopeChanged; + public void Dispose() { asyncLock?.Dispose(); @@ -184,4 +193,9 @@ public void Dispose() private BindingConfigurationDto GetBinding(string connectionId, string sonarProjectKey) => connectionId is not null ? new BindingConfigurationDto(connectionId, sonarProjectKey) : null; + + private void OnCurrentConfigurationScopeChanged() + { + CurrentConfigurationScopeChanged?.Invoke(this, EventArgs.Empty); + } }