From 8c07a2343b823a6b9b77b0006089538ae9c57c47 Mon Sep 17 00:00:00 2001 From: Chris Rudolphi <1702962+clrudolphi@users.noreply.github.com> Date: Thu, 21 Nov 2024 17:25:43 -0600 Subject: [PATCH 1/3] Proposed Fix for ReqnrollVisualStudio issue 47 (Context menu throws error in project that Step Bindings but no feature files) Partial fix; tests not passing and needing update to reflect that with this change we would allow Discovery to proceed on external binding assemblies. --- Reqnroll.VisualStudio/Discovery/DiscoveryInvoker.cs | 7 +++---- Reqnroll.VisualStudio/Discovery/DiscoveryService.cs | 3 +-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/Reqnroll.VisualStudio/Discovery/DiscoveryInvoker.cs b/Reqnroll.VisualStudio/Discovery/DiscoveryInvoker.cs index 9b4a9186..44bcc6db 100644 --- a/Reqnroll.VisualStudio/Discovery/DiscoveryInvoker.cs +++ b/Reqnroll.VisualStudio/Discovery/DiscoveryInvoker.cs @@ -21,9 +21,8 @@ public DiscoveryInvoker(IProjectScope projectScope, IDiscoveryResultProvider dis public int CreateProjectHash(ProjectSettings projectSettings, ConfigSource testAssemblySource) => projectSettings.GetHashCode() ^ testAssemblySource.GetHashCode(); - - public ConfigSource GetTestAssemblySource(ProjectSettings projectSettings) => - projectSettings.IsReqnrollTestProject + public ConfigSource GetTestAssemblySource(ProjectSettings projectSettings) => + projectSettings.IsReqnrollProject ? ConfigSource.TryGetConfigSource(projectSettings.OutputAssemblyPath, _fileSystem, _logger) : ConfigSource.CreateInvalid("The project is not detected to be a Reqnroll project, therefore some Reqnroll Visual Studio Extension features are disabled."); @@ -70,7 +69,7 @@ public Discovery(IDeveroomLogger logger, IDeveroomErrorListServices errorListSer public IDiscovery AndProjectIsReqnrollProject() { - if (_projectSettings.IsReqnrollTestProject) + if (_projectSettings.IsReqnrollProject) return this; _logger.LogVerbose("Non-Reqnroll test project"); diff --git a/Reqnroll.VisualStudio/Discovery/DiscoveryService.cs b/Reqnroll.VisualStudio/Discovery/DiscoveryService.cs index 09011b37..bf64cbd0 100644 --- a/Reqnroll.VisualStudio/Discovery/DiscoveryService.cs +++ b/Reqnroll.VisualStudio/Discovery/DiscoveryService.cs @@ -40,8 +40,7 @@ public void TriggerDiscovery([CallerMemberName] string callerMemberName = "?") { _logger.LogVerbose($"Discovery triggered from {callerMemberName}"); - _projectScope.IdeScope.FireAndForgetOnBackgroundThread( - _ => BindingRegistryCache.Update(_ => DiscoveryInvoker.InvokeDiscoveryWithTimer())); + BindingRegistryCache.Update(_ => DiscoveryInvoker.InvokeDiscoveryWithTimer()); } private void ProjectSystemOnProjectsBuilt(object sender, EventArgs eventArgs) From 0b18d1dc3499369cdc341ecbe4cb18446df6c25a Mon Sep 17 00:00:00 2001 From: Chris Rudolphi <1702962+clrudolphi@users.noreply.github.com> Date: Mon, 25 Nov 2024 14:31:41 -0600 Subject: [PATCH 2/3] Put the bulk of the FindStepUsagesCommand PreExec method body on a background Task. --- .../FindStepDefinitionUsagesCommand.cs | 58 ++++++++++--------- .../Discovery/DiscoveryTests.cs | 2 +- 2 files changed, 33 insertions(+), 27 deletions(-) diff --git a/Reqnroll.VisualStudio/Editor/Commands/FindStepDefinitionUsagesCommand.cs b/Reqnroll.VisualStudio/Editor/Commands/FindStepDefinitionUsagesCommand.cs index 588a2d90..f4cbf73f 100644 --- a/Reqnroll.VisualStudio/Editor/Commands/FindStepDefinitionUsagesCommand.cs +++ b/Reqnroll.VisualStudio/Editor/Commands/FindStepDefinitionUsagesCommand.cs @@ -53,37 +53,43 @@ public override bool PreExec(IWpfTextView textView, DeveroomEditorCommandTargetK var project = IdeScope.GetProject(textBuffer); bool bindingsNotYetLoaded = false; bool projectNotYetLoaded = project == null; - if (!projectNotYetLoaded) + var asyncContextMenu = IdeScope.Actions.ShowAsyncContextMenu(PopupHeader); + Task.Run(async () => { - Logger.LogVerbose("Find Step Definition Usages:PreExec: project loaded"); - var bindingRegistry = project.GetDiscoveryService().BindingRegistryCache; - bindingsNotYetLoaded = (bindingRegistry == null || bindingRegistry.Value == ProjectBindingRegistry.Invalid); - if (bindingsNotYetLoaded) - Logger.LogVerbose($"Find Step Definition Usages: PreExec: binding registry not available: {(bindingRegistry == null ? "null" : "invalid")}"); - } + if (!projectNotYetLoaded) + { + Logger.LogVerbose("Find Step Definition Usages:PreExec: project loaded"); + var bindingRegistry = project.GetDiscoveryService().BindingRegistryCache; + bindingsNotYetLoaded = (bindingRegistry == null || bindingRegistry.Value == ProjectBindingRegistry.Invalid); + if (bindingsNotYetLoaded) + { + Logger.LogVerbose($"Find Step Definition Usages: PreExec: binding registry not available: {(bindingRegistry == null ? "null" : "invalid")}"); + IdeScope.Actions.ShowProblem("Unable to find step definition usages: the project is not initialized yet."); + return true; + } + } - if (project == null || !project.GetProjectSettings().IsReqnrollProject || bindingsNotYetLoaded ) - { - IdeScope.Actions.ShowProblem( - "Unable to find step definition usages: the project is not detected to be a Reqnroll project or it is not initialized yet."); - return true; - } + if (project == null || !project.GetProjectSettings().IsReqnrollProject || bindingsNotYetLoaded) + { + IdeScope.Actions.ShowProblem( + "Unable to find step definition usages: the project is not detected to be a Reqnroll project."); + return true; + } - var reqnrollTestProjects = IdeScope.GetProjectsWithFeatureFiles() - .Where(p => p.GetProjectSettings().IsReqnrollTestProject) - .ToArray(); + var reqnrollTestProjects = IdeScope.GetProjectsWithFeatureFiles() + .Where(p => p.GetProjectSettings().IsReqnrollTestProject) + .ToArray(); - if (reqnrollTestProjects.Length == 0) - { - IdeScope.Actions.ShowProblem( - "Unable to find step definition usages: could not find any Reqnroll project with feature files."); - return true; - } + if (reqnrollTestProjects.Length == 0) + { + IdeScope.Actions.ShowProblem( + "Unable to find step definition usages: could not find any Reqnroll project with feature files."); + return true; + } - var asyncContextMenu = IdeScope.Actions.ShowAsyncContextMenu(PopupHeader); - Task.Run( - () => FindUsagesInProjectsAsync(reqnrollTestProjects, fileName, triggerPoint, asyncContextMenu, - asyncContextMenu.CancellationToken), asyncContextMenu.CancellationToken); + await FindUsagesInProjectsAsync(reqnrollTestProjects, fileName, triggerPoint, asyncContextMenu, asyncContextMenu.CancellationToken); + return true; + }, asyncContextMenu.CancellationToken); return true; } diff --git a/Tests/Reqnroll.VisualStudio.Tests/Discovery/DiscoveryTests.cs b/Tests/Reqnroll.VisualStudio.Tests/Discovery/DiscoveryTests.cs index afa388f9..f74c4bb9 100644 --- a/Tests/Reqnroll.VisualStudio.Tests/Discovery/DiscoveryTests.cs +++ b/Tests/Reqnroll.VisualStudio.Tests/Discovery/DiscoveryTests.cs @@ -114,7 +114,7 @@ public void DoNotDiscoverWhenProjectIsNotReqnrollTestProject() { //arrange using var sut = ArrangeSut(); - sut.ProjectScope.StubProjectSettingsProvider.Kind = DeveroomProjectKind.ReqnrollLibProject; + sut.ProjectScope.StubProjectSettingsProvider.Kind = DeveroomProjectKind.OtherProject; DiscoveryInvoker discoveryInvoker = sut.BuildDiscoveryInvoker(); From 1ce839cb4c97e5d3a2fa88113989eeda64620d0f Mon Sep 17 00:00:00 2001 From: Chris Rudolphi <1702962+clrudolphi@users.noreply.github.com> Date: Tue, 26 Nov 2024 21:23:37 -0600 Subject: [PATCH 3/3] Reverting change to DiscoveryService so that the method TriggerDiscovery() causes the BindingCache update to be run on a fire&forget worker thread. --- Reqnroll.VisualStudio/Discovery/DiscoveryService.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Reqnroll.VisualStudio/Discovery/DiscoveryService.cs b/Reqnroll.VisualStudio/Discovery/DiscoveryService.cs index bf64cbd0..09011b37 100644 --- a/Reqnroll.VisualStudio/Discovery/DiscoveryService.cs +++ b/Reqnroll.VisualStudio/Discovery/DiscoveryService.cs @@ -40,7 +40,8 @@ public void TriggerDiscovery([CallerMemberName] string callerMemberName = "?") { _logger.LogVerbose($"Discovery triggered from {callerMemberName}"); - BindingRegistryCache.Update(_ => DiscoveryInvoker.InvokeDiscoveryWithTimer()); + _projectScope.IdeScope.FireAndForgetOnBackgroundThread( + _ => BindingRegistryCache.Update(_ => DiscoveryInvoker.InvokeDiscoveryWithTimer())); } private void ProjectSystemOnProjectsBuilt(object sender, EventArgs eventArgs)