Skip to content

Commit

Permalink
Merge pull request #57878 from JoeRobich/backport-lightbulb-fix
Browse files Browse the repository at this point in the history
Backport integration test fixes to dev17.0-vs-deps
  • Loading branch information
JoeRobich committed Nov 19, 2021
2 parents 6ab6601 + 3ad27ed commit bbd4111
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -332,18 +332,5 @@ public override int GetHashCode()
}

#endregion

internal TestAccessor GetTestAccessor()
=> new TestAccessor(this);

internal readonly struct TestAccessor
{
private readonly SuggestedAction _suggestedAction;

public TestAccessor(SuggestedAction suggestedAction)
=> _suggestedAction = suggestedAction;

public ref bool IsApplied => ref _suggestedAction._isApplied;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.Text.Operations;
using Microsoft.VisualStudio.Text.Tagging;
using Microsoft.VisualStudio.Utilities;
using Roslyn.Utilities;
using OLECMDEXECOPT = Microsoft.VisualStudio.OLE.Interop.OLECMDEXECOPT;
using ThreadHelper = Microsoft.VisualStudio.Shell.ThreadHelper;
Expand Down Expand Up @@ -69,11 +70,10 @@ public void ShowLightBulb()
InvokeOnUIThread(cancellationToken =>
{
var shell = GetGlobalService<SVsUIShell, IVsUIShell>();
var cmdGroup = typeof(VSConstants.VSStd2KCmdID).GUID;
var cmdGroup = typeof(VSConstants.VSStd14CmdID).GUID;
var cmdExecOpt = OLECMDEXECOPT.OLECMDEXECOPT_DONTPROMPTUSER;
const VSConstants.VSStd2KCmdID ECMD_SMARTTASKS = (VSConstants.VSStd2KCmdID)147;
var cmdID = ECMD_SMARTTASKS;
var cmdID = VSConstants.VSStd14CmdID.ShowQuickFixes;
object? obj = null;
shell.PostExecCommand(cmdGroup, (uint)cmdID, (uint)cmdExecOpt, ref obj);
});
Expand Down Expand Up @@ -446,9 +446,26 @@ private Func<IWpfTextView, Task<bool>> GetLightBulbApplicationAction(string acti
broker.DismissSession(view);
}
action.Invoke(CancellationToken.None);
return action is not SuggestedAction suggestedAction
|| suggestedAction.GetTestAccessor().IsApplied;
if (action is not SuggestedAction suggestedAction)
return true;
broker.DismissSession(view);
var threadOperationExecutor = GetComponentModelService<IUIThreadOperationExecutor>();
var guardedOperations = GetComponentModelService<IGuardedOperations2>();
threadOperationExecutor.Execute(
title: "Execute Suggested Action",
defaultDescription: Accelerator.StripAccelerators(action.DisplayText, '_'),
allowCancellation: true,
showProgress: true,
action: context =>
{
guardedOperations.CallExtensionPoint(
errorSource: suggestedAction,
call: () => suggestedAction.Invoke(context),
exceptionGuardFilter: e => e is not OperationCanceledException);
});
return true;
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,16 @@ public void ActivateMainWindow()
var activeVisualStudioWindow = (IntPtr)dte.ActiveWindow.HWnd;
Debug.WriteLine($"DTE.ActiveWindow.HWnd = {activeVisualStudioWindow}");
if (activeVisualStudioWindow == IntPtr.Zero)
if (activeVisualStudioWindow != IntPtr.Zero)
{
activeVisualStudioWindow = (IntPtr)dte.MainWindow.HWnd;
Debug.WriteLine($"DTE.MainWindow.HWnd = {activeVisualStudioWindow}");
if (IntegrationHelper.TrySetForegroundWindow(activeVisualStudioWindow))
return;
}
IntegrationHelper.SetForegroundWindow(activeVisualStudioWindow);
activeVisualStudioWindow = dte.MainWindow.HWnd;
Debug.WriteLine($"DTE.MainWindow.HWnd = {activeVisualStudioWindow}");
if (!IntegrationHelper.TrySetForegroundWindow(activeVisualStudioWindow))
throw new InvalidOperationException("Failed to set the foreground window.");
});

public int GetErrorListErrorCount()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ public static void KillProcess(string processName)
}
}

public static void SetForegroundWindow(IntPtr window)
public static bool TrySetForegroundWindow(IntPtr window)
{
var activeWindow = NativeMethods.GetLastActivePopup(window);
activeWindow = NativeMethods.IsWindowVisible(activeWindow) ? activeWindow : window;
Expand Down Expand Up @@ -213,9 +213,11 @@ public static void SetForegroundWindow(IntPtr window)

if (!NativeMethods.SetForegroundWindow(activeWindow))
{
throw new InvalidOperationException("Failed to set the foreground window.");
return false;
}
}

return true;
}

public static void SendInput(NativeMethods.INPUT[] inputs)
Expand Down
39 changes: 24 additions & 15 deletions src/VisualStudio/IntegrationTest/TestUtilities/LightBulbHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.VisualStudio.Language.Intellisense;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.Threading;

namespace Microsoft.VisualStudio.IntegrationTest.Utilities
{
Expand Down Expand Up @@ -51,25 +53,32 @@ public static async Task<IEnumerable<SuggestedActionSet>> WaitForItemsAsync(ILig
throw new InvalidOperationException(string.Format("No expanded light bulb session found after View.ShowSmartTag. Buffer content type={0}", bufferType));
}

var start = DateTime.Now;
IEnumerable<SuggestedActionSet> actionSets = Array.Empty<SuggestedActionSet>();
while (DateTime.Now - start < Helper.HangMitigatingTimeout)
var asyncSession = (IAsyncLightBulbSession)activeSession;
var tcs = new TaskCompletionSource<List<SuggestedActionSet>>();

EventHandler<SuggestedActionsUpdatedArgs>? handler = null;
handler = (s, e) =>
{
var status = activeSession.TryGetSuggestedActionSets(out actionSets);
if (status is not QuerySuggestedActionCompletionStatus.Completed and
not QuerySuggestedActionCompletionStatus.Canceled)
{
await Task.Delay(TimeSpan.FromSeconds(1));
continue;
}
// ignore these. we care about when the lightbulb items are all completed.
if (e.Status == QuerySuggestedActionCompletionStatus.InProgress)
return;
if (status != QuerySuggestedActionCompletionStatus.Completed)
actionSets = Array.Empty<SuggestedActionSet>();
if (e.Status == QuerySuggestedActionCompletionStatus.Completed)
tcs.SetResult(e.ActionSets.ToList());
else
tcs.SetException(new InvalidOperationException($"Light bulb transitioned to non-complete state: {e.Status}"));
break;
}
asyncSession.SuggestedActionsUpdated -= handler;
};

asyncSession.SuggestedActionsUpdated += handler;

// Calling PopulateWithData ensures the underlying session will call SuggestedActionsUpdated at least once
// with the latest data computed. This is needed so that if the lightbulb computation is already complete
// that we hear about the results.
asyncSession.PopulateWithData(overrideRequestedActionCategories: null, operationContext: null);

return actionSets;
return await tcs.Task.WithTimeout(Helper.HangMitigatingTimeout).ConfigureAwait(false);
}
}
}

0 comments on commit bbd4111

Please sign in to comment.